list-helper-evo.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <script setup lang="ts" generic="T extends AnyObject">
  2. import { onUnmounted, UnwrapRef } from 'vue'
  3. const props = withDefaults(
  4. defineProps<{
  5. request?: (query: Partial<T>) => Promise<IResData<T[]>>
  6. items?: T[]
  7. query?: Partial<T>
  8. automatic?: boolean
  9. mockList?: Partial<T>[]
  10. contentClass?: string
  11. customClass?: string
  12. }>(),
  13. {
  14. automatic: true,
  15. query: () => ({}),
  16. contentClass: 'flex flex-col',
  17. },
  18. )
  19. const slot = defineSlots<{
  20. default(props: { item: UnwrapRef<T>; index: number; isLast: boolean }): any
  21. list(props: { list: UnwrapRef<T[]> }): any
  22. }>()
  23. const request = computed(() => {
  24. if (props.request) {
  25. return props.request
  26. } else {
  27. return async () => {
  28. return { code: 0, msg: '', data: props.items }
  29. }
  30. }
  31. })
  32. const data = ref()
  33. const setData = async () => {
  34. data.value = []
  35. const { data: resData } = await request.value({ ...props.query })
  36. data.value = resData
  37. }
  38. const list = ref([])
  39. onMounted(async () => {
  40. console.log('mounted')
  41. if (props.mockList) {
  42. data.value = props.mockList as T[]
  43. return
  44. }
  45. if (props.automatic) {
  46. await setData()
  47. }
  48. })
  49. watch(
  50. () => props.query,
  51. async () => {
  52. if (props.mockList) {
  53. data.value = props.mockList as T[]
  54. return
  55. }
  56. await setData()
  57. },
  58. )
  59. watch(
  60. () => props.items,
  61. () => {
  62. data.value = props.items
  63. },
  64. )
  65. watch(
  66. () => data.value,
  67. () => {
  68. list.value = data.value
  69. },
  70. { deep: true },
  71. )
  72. defineExpose({
  73. reload: async () => {
  74. await setData()
  75. },
  76. })
  77. onUnmounted(() => {
  78. console.log('unmounted')
  79. })
  80. </script>
  81. <script lang="ts">
  82. export default {
  83. options: {
  84. virtualHost: true,
  85. styleIsolation: 'shared',
  86. },
  87. }
  88. </script>
  89. <template>
  90. <div class="flex-grow relative flex flex-col" :class="customClass">
  91. <div :class="contentClass">
  92. <!-- {{ list }}-->
  93. <template v-if="slot.default">
  94. <template v-for="(it, index) in list" :key="index">
  95. <slot
  96. :item="it as UnwrapRef<T>"
  97. :index="index"
  98. :isLast="index == (list?.length ?? 0) - 1"
  99. ></slot>
  100. </template>
  101. </template>
  102. <slot name="list" :list="list"></slot>
  103. </div>
  104. <div
  105. v-if="mockList"
  106. class="construction-dashed absolute top-0 right-0 left-0 bottom-0 bg-red/20 flex items-center justify-center pointer-events-none"
  107. >
  108. <div class="text-16 text-black/30">Debug</div>
  109. </div>
  110. </div>
  111. </template>
  112. <style scoped lang="scss">
  113. //@layer utilities {
  114. .construction-dashed {
  115. @apply border-4 border-black/50 border-dashed; /* 基础虚线样式 */
  116. animation: dashed-move 2s linear infinite; /* 虚线移动动画 */
  117. }
  118. //}
  119. @keyframes dashed-move {
  120. from {
  121. border-spacing: 0;
  122. }
  123. to {
  124. border-spacing: 10px;
  125. }
  126. }
  127. </style>