StdCurd.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <script setup lang="ts">
  2. import { message } from 'ant-design-vue'
  3. import type { ComputedRef } from 'vue'
  4. import type { StdTableProps } from './StdTable.vue'
  5. import StdTable from './StdTable.vue'
  6. import gettext from '@/gettext'
  7. import StdDataEntry from '@/components/StdDesign/StdDataEntry'
  8. import type { Column } from '@/components/StdDesign/types'
  9. export interface StdCurdProps {
  10. cardTitleKey?: string
  11. modalMaxWidth?: string | number
  12. disableAdd?: boolean
  13. onClickAdd?: () => void
  14. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  15. onClickEdit?: (id: number | string, record: any, index: number) => void
  16. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  17. beforeSave?: (data: any) => void
  18. }
  19. const props = defineProps<StdTableProps & StdCurdProps>()
  20. const { $gettext } = gettext
  21. const visible = ref(false)
  22. const update = ref(0)
  23. const data = reactive({ id: null })
  24. provide('data', data)
  25. const error = reactive({})
  26. const selected = ref([])
  27. function onSelect(keys) {
  28. selected.value = keys
  29. }
  30. const editableColumns = computed(() => {
  31. return props.columns!.filter(c => {
  32. return c.edit
  33. })
  34. }) as ComputedRef<Column[]>
  35. function add() {
  36. Object.keys(data).forEach(v => {
  37. delete data[v]
  38. })
  39. clear_error()
  40. visible.value = true
  41. }
  42. const table = ref()
  43. function get_list() {
  44. table.value?.get_list()
  45. }
  46. defineExpose({
  47. add,
  48. get_list,
  49. data,
  50. })
  51. function clear_error() {
  52. Object.keys(error).forEach(v => {
  53. delete error[v]
  54. })
  55. }
  56. const ok = async () => {
  57. clear_error()
  58. await props?.beforeSave?.(data)
  59. props.api!.save(data.id, data).then(r => {
  60. message.success($gettext('Save Successfully'))
  61. Object.assign(data, r)
  62. get_list()
  63. visible.value = false
  64. }).catch(e => {
  65. message.error($gettext(e?.message ?? 'Server error'), 5)
  66. Object.assign(error, e.errors)
  67. })
  68. }
  69. function cancel() {
  70. visible.value = false
  71. clear_error()
  72. }
  73. function edit(id) {
  74. props.api!.get(id).then(async r => {
  75. Object.keys(data).forEach(k => {
  76. delete data[k]
  77. })
  78. data.id = null
  79. Object.assign(data, r)
  80. visible.value = true
  81. }).catch(e => {
  82. message.error($gettext(e?.message ?? 'Server error'), 5)
  83. })
  84. }
  85. const selectedRowKeys = ref([])
  86. </script>
  87. <template>
  88. <div class="std-curd">
  89. <ACard :title="title || $gettext('Table')">
  90. <template
  91. v-if="!disableAdd"
  92. #extra
  93. >
  94. <a @click="add">{{ $gettext('Add') }}</a>
  95. </template>
  96. <StdTable
  97. ref="table"
  98. v-bind="props"
  99. :key="update"
  100. v-model:selected-row-keys="selectedRowKeys"
  101. @click-edit="edit"
  102. @selected="onSelect"
  103. >
  104. <template #actions="slotProps">
  105. <slot
  106. name="actions"
  107. :actions="slotProps.record"
  108. />
  109. </template>
  110. </StdTable>
  111. </ACard>
  112. <AModal
  113. class="std-curd-edit-modal"
  114. :mask="false"
  115. :title="data.id ? $gettext('Modify') : $gettext('Add')"
  116. :open="visible"
  117. :cancel-text="$gettext('Cancel')"
  118. :ok-text="$gettext('OK')"
  119. :width="modalMaxWidth"
  120. destroy-on-close
  121. @cancel="cancel"
  122. @ok="ok"
  123. >
  124. <div
  125. v-if="$slots.beforeEdit"
  126. class="before-edit"
  127. >
  128. <slot
  129. name="beforeEdit"
  130. :data="data"
  131. />
  132. </div>
  133. <StdDataEntry
  134. :data-list="editableColumns"
  135. :data-source="data"
  136. :error="error"
  137. />
  138. <slot
  139. name="edit"
  140. :data="data"
  141. />
  142. </AModal>
  143. </div>
  144. </template>
  145. <style lang="less" scoped>
  146. :deep(.before-edit:last-child) {
  147. margin-bottom: 20px;
  148. }
  149. </style>