diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts new file mode 100644 index 0000000..857408d --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts @@ -0,0 +1,692 @@ +export type PaginationType = { + current : number, + size : number, + count : number +} + +export type LoadMoreType = { + contentdown : string, + contentrefresh : string, + contentnomore : string +} + +export type SelectedItemType = { + name : string, + value : string, +} + +export type GetCommandOptions = { + collection ?: UTSJSONObject, + field ?: string, + orderby ?: string, + where ?: any, + pageData ?: string, + pageCurrent ?: number, + pageSize ?: number, + getCount ?: boolean, + getTree ?: any, + getTreePath ?: UTSJSONObject, + startwith ?: string, + limitlevel ?: number, + groupby ?: string, + groupField ?: string, + distinct ?: boolean, + pageIndistinct ?: boolean, + foreignKey ?: string, + loadtime ?: string, + manual ?: boolean +} + +const DefaultSelectedNode = { + text: '请选择', + value: '' +} + +export const dataPicker = defineMixin({ + props: { + localdata: { + type: Array as PropType>, + default: [] as Array + }, + collection: { + type: Object, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: Object, + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 20 + }, + getcount: { + type: Boolean, + default: false + }, + gettree: { + type: Object, + default: '' + }, + gettreepath: { + type: Object, + default: '' + }, + startwith: { + type: String, + default: '' + }, + limitlevel: { + type: Number, + default: 10 + }, + groupby: { + type: String, + default: '' + }, + groupField: { + type: String, + default: '' + }, + distinct: { + type: Boolean, + default: false + }, + pageIndistinct: { + type: Boolean, + default: false + }, + foreignKey: { + type: String, + default: '' + }, + loadtime: { + type: String, + default: 'auto' + }, + manual: { + type: Boolean, + default: false + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + value: { + type: Object, + default: '' + }, + modelValue: { + type: Object, + default: '' + }, + defaultProps: { + type: Object as PropType, + } + }, + data() { + return { + loading: false, + error: null as UniCloudError | null, + treeData: [] as Array, + selectedIndex: 0, + selectedNodes: [] as Array, + selectedPages: [] as Array[], + selectedValue: '', + selectedPaths: [] as Array, + pagination: { + current: 1, + size: 20, + count: 0 + } as PaginationType + } + }, + computed: { + mappingTextName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text' + }, + mappingValueName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value' + }, + currentDataList() : Array { + if (this.selectedIndex > this.selectedPages.length - 1) { + return [] as Array + } + return this.selectedPages[this.selectedIndex] + }, + isLocalData() : boolean { + return this.localdata.length > 0 + }, + isCloudData() : boolean { + return this._checkIsNotNull(this.collection) + }, + isCloudDataList() : boolean { + return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0)) + }, + isCloudDataTree() : boolean { + return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0) + }, + dataValue() : any { + return this.hasModelValue ? this.modelValue : this.value + }, + hasCloudTreeData() : boolean { + return this.treeData.length > 0 + }, + hasModelValue() : boolean { + if (typeof this.modelValue == 'string') { + const valueString = this.modelValue as string + return (valueString.length > 0) + } else if (Array.isArray(this.modelValue)) { + const valueArray = this.modelValue as Array + return (valueArray.length > 0) + } + return false + }, + hasCloudDataValue() : boolean { + if (typeof this.dataValue == 'string') { + const valueString = this.dataValue as string + return (valueString.length > 0) + } + return false + } + }, + created() { + this.pagination.current = this.pageCurrent + this.pagination.size = this.pageSize + + this.$watch( + () : any => [ + this.pageCurrent, + this.pageSize, + this.localdata, + this.value, + this.collection, + this.field, + this.getcount, + this.orderby, + this.where, + this.groupby, + this.groupField, + this.distinct + ], + (newValue : Array, oldValue : Array) => { + this.pagination.size = this.pageSize + if (newValue[0] !== oldValue[0]) { + this.pagination.current = this.pageCurrent + } + + this.onPropsChange() + } + ) + }, + methods: { + onPropsChange() { + this.selectedIndex = 0 + this.selectedNodes.length = 0 + this.selectedPages.length = 0 + this.selectedPaths.length = 0 + + // 加载数据 + this.$nextTick(() => { + this.loadData() + }) + }, + + onTabSelect(index : number) { + this.selectedIndex = index + }, + + onNodeClick(nodeData : UTSJSONObject) { + if (nodeData.getBoolean('disable', false)) { + return + } + + const isLeaf = this._checkIsLeafNode(nodeData) + + this._trimSelectedNodes(nodeData) + + this.$emit('nodeclick', nodeData) + + if (this.isLocalData) { + if (isLeaf || !this._checkHasChildren(nodeData)) { + this.onFinish() + } + } else if (this.isCloudDataList) { + this.onFinish() + } else if (this.isCloudDataTree) { + if (isLeaf) { + this.onFinish() + } else if (!this._checkHasChildren(nodeData)) { + // 尝试请求一次,如果没有返回数据标记为叶子节点 + this.loadCloudDataNode(nodeData) + } + } + }, + + getChangeNodes(): Array { + const nodes: Array = [] + this.selectedNodes.forEach((node : UTSJSONObject) => { + const newNode: UTSJSONObject = {} + newNode[this.mappingTextName] = node.getString(this.mappingTextName) + newNode[this.mappingValueName] = node.getString(this.mappingValueName) + nodes.push(newNode) + }) + return nodes + }, + + onFinish() { }, + + // 加载数据(自动判定环境) + loadData() { + if (this.isLocalData) { + this.loadLocalData() + } else if (this.isCloudDataList) { + this.loadCloudDataList() + } else if (this.isCloudDataTree) { + this.loadCloudDataTree() + } + }, + + // 加载本地数据 + loadLocalData() { + this.treeData = this.localdata + if (Array.isArray(this.dataValue)) { + const value = this.dataValue as Array + this.selectedPaths = value.slice(0) + this._pushSelectedTreeNodes(value, this.localdata) + } else { + this._pushSelectedNodes(this.localdata) + } + }, + + // 加载 Cloud 数据 (单列) + loadCloudDataList() { + this._loadCloudData(null, (data : Array) => { + this.treeData = data + this._pushSelectedNodes(data) + }) + }, + + // 加载 Cloud 数据 (树形) + loadCloudDataTree() { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere(), + getTree: true + } as GetCommandOptions + if (this._checkIsNotNull(this.gettree)) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'` + } + this._loadCloudData(commandOptions, (data : Array) => { + this.treeData = data + if (this.selectedPaths.length > 0) { + this._pushSelectedTreeNodes(this.selectedPaths, data) + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 加载 Cloud 数据 (节点) + loadCloudDataNode(nodeData : UTSJSONObject) { + const commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + } as GetCommandOptions + this._loadCloudData(commandOptions, (data : Array) => { + nodeData['children'] = data + if (data.length == 0) { + nodeData['isleaf'] = true + this.onFinish() + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 回显 Cloud Tree Path + loadCloudDataPath() { + if (!this.hasCloudDataValue) { + return + } + + const command : GetCommandOptions = {} + + // 单列 + if (this.isCloudDataList) { + // 根据 field's as value标识匹配 where 条件 + let where : Array = []; + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + where.push(`${whereField} == '${this.dataValue as string}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + whereString = `(${this.where}) && (${whereString})` + } + + command.field = this._cloudDataPostField() + command.where = whereString + } + + // 树形 + if (this.isCloudDataTree) { + command.field = this._cloudDataPostField() + command.getTreePath = { + startWith: `${this.selfField}=='${this.dataValue as string}'` + } + } + + this._loadCloudData(command, (data : Array) => { + this._extractTreePath(data, this.selectedPaths) + }) + }, + + _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array) => void)) { + if (this.loading) { + return + } + this.loading = true + + this.error = null + + this._getCommand(options).then((response : UniCloudDBGetResult) => { + callback?.(response.data) + }).catch((err : any | null) => { + this.error = err as UniCloudError + }).finally(() => { + this.loading = false + }) + }, + + _cloudDataPostField() : string { + let fields = [this.field]; + if (this.parentField.length > 0) { + fields.push(`${this.parentField} as parent_value`) + } + return fields.join(',') + }, + + _cloudDataTreeWhere() : string { + let result : Array = [] + let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths + let parentField = this.parentField + if (parentField.length > 0) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selectedNodes.length > 0) { + for (var i = 0; i < selectedNodes.length - 1; i++) { + const parentFieldValue = selectedNodes[i].getString('value', '') + result.push(`${parentField} == '${parentFieldValue}'`) + } + } + + let where : Array = [] + if (this._checkIsNotNull(this.where)) { + where.push(`(${this.where as string})`) + } + + if (result.length > 0) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() : string { + const where : Array = [] + if (this.selectedNodes.length > 0) { + const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '') + where.push(`${this.parentField} == '${value}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + return `(${this.where as string}) && (${whereString})` + } + + return whereString + }, + + _getWhereByForeignKey() : string { + let result : Array = [] + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + result.push(`${whereField} == '${this.dataValue as string}'`) + } + + if (this._checkIsNotNull(this.where)) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() : string { + const fields = this.field.split(',') + let whereField = '' + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as') + if (items.length < 2) { + continue + } + if (items[1].trim() === 'value') { + whereField = items[0].trim() + break + } + } + return whereField + }, + + _getCommand(options ?: GetCommandOptions) : Promise { + let db = uniCloud.databaseForJQL() + + let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array)) : db.collection(this.collection) + + let filter : UniCloudDBFilter | null = null + if (this.foreignKey.length > 0) { + filter = collection.foreignKey(this.foreignKey) + } + + const where : any = options?.where ?? this.where + if (typeof where == 'string') { + const whereString = where as string + if (whereString.length > 0) { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + } else { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + + let query : UniCloudDBQuery | null = null + if (this.field.length > 0) { + query = (filter != null) ? filter.field(this.field) : collection.field(this.field) + } + if (this.groupby.length > 0) { + if (query != null) { + query = query.groupBy(this.groupby) + } else if (filter != null) { + query = filter.groupBy(this.groupby) + } + } + if (this.groupField.length > 0) { + if (query != null) { + query = query.groupField(this.groupField) + } else if (filter != null) { + query = filter.groupField(this.groupField) + } + } + if (this.distinct == true) { + if (query != null) { + query = query.distinct(this.field) + } else if (filter != null) { + query = filter.distinct(this.field) + } + } + if (this.orderby.length > 0) { + if (query != null) { + query = query.orderBy(this.orderby) + } else if (filter != null) { + query = filter.orderBy(this.orderby) + } + } + + const size = this.pagination.size + const current = this.pagination.current + if (query != null) { + query = query.skip(size * (current - 1)).limit(size) + } else if (filter != null) { + query = filter.skip(size * (current - 1)).limit(size) + } else { + query = collection.skip(size * (current - 1)).limit(size) + } + + const getOptions = {} + const treeOptions = { + limitLevel: this.limitlevel, + startWith: this.startwith + } + if (this.getcount == true) { + getOptions['getCount'] = this.getcount + } + + const getTree : any = options?.getTree ?? this.gettree + if (typeof getTree == 'string') { + const getTreeString = getTree as string + if (getTreeString.length > 0) { + getOptions['getTree'] = treeOptions + } + } else if (typeof getTree == 'object') { + getOptions['getTree'] = treeOptions + } else { + getOptions['getTree'] = getTree + } + + const getTreePath = options?.getTreePath ?? this.gettreepath + if (typeof getTreePath == 'string') { + const getTreePathString = getTreePath as string + if (getTreePathString.length > 0) { + getOptions['getTreePath'] = getTreePath + } + } else { + getOptions['getTreePath'] = getTreePath + } + + return query.get(getOptions) + }, + + _checkIsNotNull(value : any) : boolean { + if (typeof value == 'string') { + const valueString = value as string + return (valueString.length > 0) + } else if (value instanceof UTSJSONObject) { + return true + } + return false + }, + + _checkIsLeafNode(nodeData : UTSJSONObject) : boolean { + if (this.selectedIndex >= this.limitlevel) { + return true + } + + if (nodeData.getBoolean('isleaf', false)) { + return true + } + + return false + }, + + _checkHasChildren(nodeData : UTSJSONObject) : boolean { + const children = nodeData.getArray('children') ?? ([] as Array) + return children.length > 0 + }, + + _pushSelectedNodes(nodes : Array) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(nodes) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _trimSelectedNodes(nodeData : UTSJSONObject) { + this.selectedNodes.splice(this.selectedIndex) + this.selectedNodes.push(nodeData) + + if (this.selectedPages.length > 0) { + this.selectedPages.splice(this.selectedIndex + 1) + } + + const children = nodeData.getArray('children') ?? ([] as Array) + if (children.length > 0) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(children) + } + + this.selectedIndex = this.selectedPages.length - 1 + }, + + _pushSelectedTreeNodes(paths : Array, nodes : Array) { + let children : Array = nodes + paths.forEach((node : UTSJSONObject) => { + const findNode = children.find((item : UTSJSONObject) : boolean => { + return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName)) + }) + if (findNode != null) { + this.selectedPages.push(children) + this.selectedNodes.push(node) + children = findNode.getArray('children') ?? ([] as Array) + } + }) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _extractTreePath(nodes : Array, result : Array) { + if (nodes.length == 0) { + return + } + + const node = nodes[0] + result.push(node) + + const children = node.getArray('children') + if (Array.isArray(children) && children!.length > 0) { + this._extractTreePath(children, result) + } + } + } +})