uni-data-picker.uts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. export type PaginationType = {
  2. current : number,
  3. size : number,
  4. count : number
  5. }
  6. export type LoadMoreType = {
  7. contentdown : string,
  8. contentrefresh : string,
  9. contentnomore : string
  10. }
  11. export type SelectedItemType = {
  12. name : string,
  13. value : string,
  14. }
  15. export type GetCommandOptions = {
  16. collection ?: UTSJSONObject,
  17. field ?: string,
  18. orderby ?: string,
  19. where ?: any,
  20. pageData ?: string,
  21. pageCurrent ?: number,
  22. pageSize ?: number,
  23. getCount ?: boolean,
  24. getTree ?: any,
  25. getTreePath ?: UTSJSONObject,
  26. startwith ?: string,
  27. limitlevel ?: number,
  28. groupby ?: string,
  29. groupField ?: string,
  30. distinct ?: boolean,
  31. pageIndistinct ?: boolean,
  32. foreignKey ?: string,
  33. loadtime ?: string,
  34. manual ?: boolean
  35. }
  36. const DefaultSelectedNode = {
  37. text: '请选择',
  38. value: ''
  39. }
  40. export const dataPicker = defineMixin({
  41. props: {
  42. localdata: {
  43. type: Array as PropType<Array<UTSJSONObject>>,
  44. default: [] as Array<UTSJSONObject>
  45. },
  46. collection: {
  47. type: Object,
  48. default: ''
  49. },
  50. field: {
  51. type: String,
  52. default: ''
  53. },
  54. orderby: {
  55. type: String,
  56. default: ''
  57. },
  58. where: {
  59. type: Object,
  60. default: ''
  61. },
  62. pageData: {
  63. type: String,
  64. default: 'add'
  65. },
  66. pageCurrent: {
  67. type: Number,
  68. default: 1
  69. },
  70. pageSize: {
  71. type: Number,
  72. default: 20
  73. },
  74. getcount: {
  75. type: Boolean,
  76. default: false
  77. },
  78. gettree: {
  79. type: Object,
  80. default: ''
  81. },
  82. gettreepath: {
  83. type: Object,
  84. default: ''
  85. },
  86. startwith: {
  87. type: String,
  88. default: ''
  89. },
  90. limitlevel: {
  91. type: Number,
  92. default: 10
  93. },
  94. groupby: {
  95. type: String,
  96. default: ''
  97. },
  98. groupField: {
  99. type: String,
  100. default: ''
  101. },
  102. distinct: {
  103. type: Boolean,
  104. default: false
  105. },
  106. pageIndistinct: {
  107. type: Boolean,
  108. default: false
  109. },
  110. foreignKey: {
  111. type: String,
  112. default: ''
  113. },
  114. loadtime: {
  115. type: String,
  116. default: 'auto'
  117. },
  118. manual: {
  119. type: Boolean,
  120. default: false
  121. },
  122. preload: {
  123. type: Boolean,
  124. default: false
  125. },
  126. stepSearh: {
  127. type: Boolean,
  128. default: true
  129. },
  130. selfField: {
  131. type: String,
  132. default: ''
  133. },
  134. parentField: {
  135. type: String,
  136. default: ''
  137. },
  138. multiple: {
  139. type: Boolean,
  140. default: false
  141. },
  142. value: {
  143. type: Object,
  144. default: ''
  145. },
  146. modelValue: {
  147. type: Object,
  148. default: ''
  149. },
  150. defaultProps: {
  151. type: Object as PropType<UTSJSONObject>,
  152. }
  153. },
  154. data() {
  155. return {
  156. loading: false,
  157. error: null as UniCloudError | null,
  158. treeData: [] as Array<UTSJSONObject>,
  159. selectedIndex: 0,
  160. selectedNodes: [] as Array<UTSJSONObject>,
  161. selectedPages: [] as Array<UTSJSONObject>[],
  162. selectedValue: '',
  163. selectedPaths: [] as Array<UTSJSONObject>,
  164. pagination: {
  165. current: 1,
  166. size: 20,
  167. count: 0
  168. } as PaginationType
  169. }
  170. },
  171. computed: {
  172. mappingTextName() : string {
  173. // TODO
  174. return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text'
  175. },
  176. mappingValueName() : string {
  177. // TODO
  178. return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value'
  179. },
  180. currentDataList() : Array<UTSJSONObject> {
  181. if (this.selectedIndex > this.selectedPages.length - 1) {
  182. return [] as Array<UTSJSONObject>
  183. }
  184. return this.selectedPages[this.selectedIndex]
  185. },
  186. isLocalData() : boolean {
  187. return this.localdata.length > 0
  188. },
  189. isCloudData() : boolean {
  190. return this._checkIsNotNull(this.collection)
  191. },
  192. isCloudDataList() : boolean {
  193. return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0))
  194. },
  195. isCloudDataTree() : boolean {
  196. return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0)
  197. },
  198. dataValue() : any {
  199. return this.hasModelValue ? this.modelValue : this.value
  200. },
  201. hasCloudTreeData() : boolean {
  202. return this.treeData.length > 0
  203. },
  204. hasModelValue() : boolean {
  205. if (typeof this.modelValue == 'string') {
  206. const valueString = this.modelValue as string
  207. return (valueString.length > 0)
  208. } else if (Array.isArray(this.modelValue)) {
  209. const valueArray = this.modelValue as Array<string>
  210. return (valueArray.length > 0)
  211. }
  212. return false
  213. },
  214. hasCloudDataValue() : boolean {
  215. if (typeof this.dataValue == 'string') {
  216. const valueString = this.dataValue as string
  217. return (valueString.length > 0)
  218. }
  219. return false
  220. }
  221. },
  222. created() {
  223. this.pagination.current = this.pageCurrent
  224. this.pagination.size = this.pageSize
  225. this.$watch(
  226. () : any => [
  227. this.pageCurrent,
  228. this.pageSize,
  229. this.localdata,
  230. this.value,
  231. this.collection,
  232. this.field,
  233. this.getcount,
  234. this.orderby,
  235. this.where,
  236. this.groupby,
  237. this.groupField,
  238. this.distinct
  239. ],
  240. (newValue : Array<any>, oldValue : Array<any>) => {
  241. this.pagination.size = this.pageSize
  242. if (newValue[0] !== oldValue[0]) {
  243. this.pagination.current = this.pageCurrent
  244. }
  245. this.onPropsChange()
  246. }
  247. )
  248. },
  249. methods: {
  250. onPropsChange() {
  251. this.selectedIndex = 0
  252. this.treeData.length = 0
  253. this.selectedNodes.length = 0
  254. this.selectedPages.length = 0
  255. this.selectedPaths.length = 0
  256. // 加载数据
  257. this.$nextTick(() => {
  258. this.loadData()
  259. })
  260. },
  261. onTabSelect(index : number) {
  262. this.selectedIndex = index
  263. },
  264. onNodeClick(nodeData : UTSJSONObject) {
  265. if (nodeData.getBoolean('disable', false)) {
  266. return
  267. }
  268. const isLeaf = this._checkIsLeafNode(nodeData)
  269. this._trimSelectedNodes(nodeData)
  270. this.$emit('nodeclick', nodeData)
  271. if (this.isLocalData) {
  272. if (isLeaf || !this._checkHasChildren(nodeData)) {
  273. this.onFinish()
  274. }
  275. } else if (this.isCloudDataList) {
  276. this.onFinish()
  277. } else if (this.isCloudDataTree) {
  278. if (isLeaf) {
  279. this.onFinish()
  280. } else if (!this._checkHasChildren(nodeData)) {
  281. // 尝试请求一次,如果没有返回数据标记为叶子节点
  282. this.loadCloudDataNode(nodeData)
  283. }
  284. }
  285. },
  286. getChangeNodes(): Array<UTSJSONObject> {
  287. const nodes: Array<UTSJSONObject> = []
  288. this.selectedNodes.forEach((node : UTSJSONObject) => {
  289. const newNode: UTSJSONObject = {}
  290. newNode[this.mappingTextName] = node.getString(this.mappingTextName)
  291. newNode[this.mappingValueName] = node.getString(this.mappingValueName)
  292. nodes.push(newNode)
  293. })
  294. return nodes
  295. },
  296. onFinish() { },
  297. // 加载数据(自动判定环境)
  298. loadData() {
  299. if (this.isLocalData) {
  300. this.loadLocalData()
  301. } else if (this.isCloudDataList) {
  302. this.loadCloudDataList()
  303. } else if (this.isCloudDataTree) {
  304. this.loadCloudDataTree()
  305. }
  306. },
  307. // 加载本地数据
  308. loadLocalData() {
  309. this.treeData = this.localdata
  310. if (Array.isArray(this.dataValue)) {
  311. const value = this.dataValue as Array<UTSJSONObject>
  312. this.selectedPaths = value.slice(0)
  313. this._pushSelectedTreeNodes(value, this.localdata)
  314. } else {
  315. this._pushSelectedNodes(this.localdata)
  316. }
  317. },
  318. // 加载 Cloud 数据 (单列)
  319. loadCloudDataList() {
  320. this._loadCloudData(null, (data : Array<UTSJSONObject>) => {
  321. this.treeData = data
  322. this._pushSelectedNodes(data)
  323. })
  324. },
  325. // 加载 Cloud 数据 (树形)
  326. loadCloudDataTree() {
  327. let commandOptions = {
  328. field: this._cloudDataPostField(),
  329. where: this._cloudDataTreeWhere(),
  330. getTree: true
  331. } as GetCommandOptions
  332. if (this._checkIsNotNull(this.gettree)) {
  333. commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'`
  334. }
  335. this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
  336. this.treeData = data
  337. if (this.selectedPaths.length > 0) {
  338. this._pushSelectedTreeNodes(this.selectedPaths, data)
  339. } else {
  340. this._pushSelectedNodes(data)
  341. }
  342. })
  343. },
  344. // 加载 Cloud 数据 (节点)
  345. loadCloudDataNode(nodeData : UTSJSONObject) {
  346. const commandOptions = {
  347. field: this._cloudDataPostField(),
  348. where: this._cloudDataNodeWhere()
  349. } as GetCommandOptions
  350. this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
  351. nodeData['children'] = data
  352. if (data.length == 0) {
  353. nodeData['isleaf'] = true
  354. this.onFinish()
  355. } else {
  356. this._pushSelectedNodes(data)
  357. }
  358. })
  359. },
  360. // 回显 Cloud Tree Path
  361. loadCloudDataPath() {
  362. if (!this.hasCloudDataValue) {
  363. return
  364. }
  365. const command : GetCommandOptions = {}
  366. // 单列
  367. if (this.isCloudDataList) {
  368. // 根据 field's as value标识匹配 where 条件
  369. let where : Array<string> = [];
  370. let whereField = this._getForeignKeyByField();
  371. if (whereField.length > 0) {
  372. where.push(`${whereField} == '${this.dataValue as string}'`)
  373. }
  374. let whereString = where.join(' || ')
  375. if (this._checkIsNotNull(this.where)) {
  376. whereString = `(${this.where}) && (${whereString})`
  377. }
  378. command.field = this._cloudDataPostField()
  379. command.where = whereString
  380. }
  381. // 树形
  382. if (this.isCloudDataTree) {
  383. command.field = this._cloudDataPostField()
  384. command.getTreePath = {
  385. startWith: `${this.selfField}=='${this.dataValue as string}'`
  386. }
  387. }
  388. this._loadCloudData(command, (data : Array<UTSJSONObject>) => {
  389. this._extractTreePath(data, this.selectedPaths)
  390. })
  391. },
  392. _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array<UTSJSONObject>) => void)) {
  393. if (this.loading) {
  394. return
  395. }
  396. this.loading = true
  397. this.error = null
  398. this._getCommand(options).then((response : UniCloudDBGetResult) => {
  399. callback?.(response.data)
  400. }).catch((err : any | null) => {
  401. this.error = err as UniCloudError
  402. }).finally(() => {
  403. this.loading = false
  404. })
  405. },
  406. _cloudDataPostField() : string {
  407. let fields = [this.field];
  408. if (this.parentField.length > 0) {
  409. fields.push(`${this.parentField} as parent_value`)
  410. }
  411. return fields.join(',')
  412. },
  413. _cloudDataTreeWhere() : string {
  414. let result : Array<string> = []
  415. let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths
  416. let parentField = this.parentField
  417. if (parentField.length > 0) {
  418. result.push(`${parentField} == null || ${parentField} == ""`)
  419. }
  420. if (selectedNodes.length > 0) {
  421. for (var i = 0; i < selectedNodes.length - 1; i++) {
  422. const parentFieldValue = selectedNodes[i].getString('value', '')
  423. result.push(`${parentField} == '${parentFieldValue}'`)
  424. }
  425. }
  426. let where : Array<string> = []
  427. if (this._checkIsNotNull(this.where)) {
  428. where.push(`(${this.where as string})`)
  429. }
  430. if (result.length > 0) {
  431. where.push(`(${result.join(' || ')})`)
  432. }
  433. return where.join(' && ')
  434. },
  435. _cloudDataNodeWhere() : string {
  436. const where : Array<string> = []
  437. if (this.selectedNodes.length > 0) {
  438. const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '')
  439. where.push(`${this.parentField} == '${value}'`)
  440. }
  441. let whereString = where.join(' || ')
  442. if (this._checkIsNotNull(this.where)) {
  443. return `(${this.where as string}) && (${whereString})`
  444. }
  445. return whereString
  446. },
  447. _getWhereByForeignKey() : string {
  448. let result : Array<string> = []
  449. let whereField = this._getForeignKeyByField();
  450. if (whereField.length > 0) {
  451. result.push(`${whereField} == '${this.dataValue as string}'`)
  452. }
  453. if (this._checkIsNotNull(this.where)) {
  454. return `(${this.where}) && (${result.join(' || ')})`
  455. }
  456. return result.join(' || ')
  457. },
  458. _getForeignKeyByField() : string {
  459. const fields = this.field.split(',')
  460. let whereField = ''
  461. for (let i = 0; i < fields.length; i++) {
  462. const items = fields[i].split('as')
  463. if (items.length < 2) {
  464. continue
  465. }
  466. if (items[1].trim() === 'value') {
  467. whereField = items[0].trim()
  468. break
  469. }
  470. }
  471. return whereField
  472. },
  473. _getCommand(options ?: GetCommandOptions) : Promise<UniCloudDBGetResult> {
  474. let db = uniCloud.databaseForJQL()
  475. let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array<any>)) : db.collection(this.collection)
  476. let filter : UniCloudDBFilter | null = null
  477. if (this.foreignKey.length > 0) {
  478. filter = collection.foreignKey(this.foreignKey)
  479. }
  480. const where : any = options?.where ?? this.where
  481. if (typeof where == 'string') {
  482. const whereString = where as string
  483. if (whereString.length > 0) {
  484. filter = (filter != null) ? filter.where(where) : collection.where(where)
  485. }
  486. } else {
  487. filter = (filter != null) ? filter.where(where) : collection.where(where)
  488. }
  489. let query : UniCloudDBQuery | null = null
  490. if (this.field.length > 0) {
  491. query = (filter != null) ? filter.field(this.field) : collection.field(this.field)
  492. }
  493. if (this.groupby.length > 0) {
  494. if (query != null) {
  495. query = query.groupBy(this.groupby)
  496. } else if (filter != null) {
  497. query = filter.groupBy(this.groupby)
  498. }
  499. }
  500. if (this.groupField.length > 0) {
  501. if (query != null) {
  502. query = query.groupField(this.groupField)
  503. } else if (filter != null) {
  504. query = filter.groupField(this.groupField)
  505. }
  506. }
  507. if (this.distinct == true) {
  508. if (query != null) {
  509. query = query.distinct(this.field)
  510. } else if (filter != null) {
  511. query = filter.distinct(this.field)
  512. }
  513. }
  514. if (this.orderby.length > 0) {
  515. if (query != null) {
  516. query = query.orderBy(this.orderby)
  517. } else if (filter != null) {
  518. query = filter.orderBy(this.orderby)
  519. }
  520. }
  521. const size = this.pagination.size
  522. const current = this.pagination.current
  523. if (query != null) {
  524. query = query.skip(size * (current - 1)).limit(size)
  525. } else if (filter != null) {
  526. query = filter.skip(size * (current - 1)).limit(size)
  527. } else {
  528. query = collection.skip(size * (current - 1)).limit(size)
  529. }
  530. const getOptions = {}
  531. const treeOptions = {
  532. limitLevel: this.limitlevel,
  533. startWith: this.startwith
  534. }
  535. if (this.getcount == true) {
  536. getOptions['getCount'] = this.getcount
  537. }
  538. const getTree : any = options?.getTree ?? this.gettree
  539. if (typeof getTree == 'string') {
  540. const getTreeString = getTree as string
  541. if (getTreeString.length > 0) {
  542. getOptions['getTree'] = treeOptions
  543. }
  544. } else if (typeof getTree == 'object') {
  545. getOptions['getTree'] = treeOptions
  546. } else {
  547. getOptions['getTree'] = getTree
  548. }
  549. const getTreePath = options?.getTreePath ?? this.gettreepath
  550. if (typeof getTreePath == 'string') {
  551. const getTreePathString = getTreePath as string
  552. if (getTreePathString.length > 0) {
  553. getOptions['getTreePath'] = getTreePath
  554. }
  555. } else {
  556. getOptions['getTreePath'] = getTreePath
  557. }
  558. return query.get(getOptions)
  559. },
  560. _checkIsNotNull(value : any) : boolean {
  561. if (typeof value == 'string') {
  562. const valueString = value as string
  563. return (valueString.length > 0)
  564. } else if (value instanceof UTSJSONObject) {
  565. return true
  566. }
  567. return false
  568. },
  569. _checkIsLeafNode(nodeData : UTSJSONObject) : boolean {
  570. if (this.selectedIndex >= this.limitlevel) {
  571. return true
  572. }
  573. if (nodeData.getBoolean('isleaf', false)) {
  574. return true
  575. }
  576. return false
  577. },
  578. _checkHasChildren(nodeData : UTSJSONObject) : boolean {
  579. const children = nodeData.getArray('children') ?? ([] as Array<any>)
  580. return children.length > 0
  581. },
  582. _pushSelectedNodes(nodes : Array<UTSJSONObject>) {
  583. this.selectedNodes.push(DefaultSelectedNode)
  584. this.selectedPages.push(nodes)
  585. this.selectedIndex = this.selectedPages.length - 1
  586. },
  587. _trimSelectedNodes(nodeData : UTSJSONObject) {
  588. this.selectedNodes.splice(this.selectedIndex)
  589. this.selectedNodes.push(nodeData)
  590. if (this.selectedPages.length > 0) {
  591. this.selectedPages.splice(this.selectedIndex + 1)
  592. }
  593. const children = nodeData.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
  594. if (children.length > 0) {
  595. this.selectedNodes.push(DefaultSelectedNode)
  596. this.selectedPages.push(children)
  597. }
  598. this.selectedIndex = this.selectedPages.length - 1
  599. },
  600. _pushSelectedTreeNodes(paths : Array<UTSJSONObject>, nodes : Array<UTSJSONObject>) {
  601. let children : Array<UTSJSONObject> = nodes
  602. paths.forEach((node : UTSJSONObject) => {
  603. const findNode = children.find((item : UTSJSONObject) : boolean => {
  604. return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName))
  605. })
  606. if (findNode != null) {
  607. this.selectedPages.push(children)
  608. this.selectedNodes.push(node)
  609. children = findNode.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
  610. }
  611. })
  612. this.selectedIndex = this.selectedPages.length - 1
  613. },
  614. _extractTreePath(nodes : Array<UTSJSONObject>, result : Array<UTSJSONObject>) {
  615. if (nodes.length == 0) {
  616. return
  617. }
  618. const node = nodes[0]
  619. result.push(node)
  620. const children = node.getArray<UTSJSONObject>('children')
  621. if (Array.isArray(children) && children!.length > 0) {
  622. this._extractTreePath(children, result)
  623. }
  624. }
  625. }
  626. })