Menu.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <script setup lang="tsx">
  2. import { reactive, ref, unref } from 'vue'
  3. import { getMenuListApi } from '@/api/menu'
  4. import { useTable } from '@/hooks/web/useTable'
  5. import { useI18n } from '@/hooks/web/useI18n'
  6. import { Table, TableColumn } from '@/components/Table'
  7. import { ElButton, ElTag } from 'element-plus'
  8. import { Icon } from '@/components/Icon'
  9. import { Search } from '@/components/Search'
  10. import { FormSchema } from '@/components/Form'
  11. import { ContentWrap } from '@/components/ContentWrap'
  12. import Write from './components/Write.vue'
  13. import { Dialog } from '@/components/Dialog'
  14. const { t } = useI18n()
  15. const { tableRegister, tableState, tableMethods } = useTable({
  16. fetchDataApi: async () => {
  17. const res = await getMenuListApi()
  18. return {
  19. list: res.data.list || []
  20. }
  21. }
  22. })
  23. const { dataList, loading } = tableState
  24. const { getList } = tableMethods
  25. const tableColumns = reactive<TableColumn[]>([
  26. {
  27. field: 'index',
  28. label: t('userDemo.index'),
  29. type: 'index'
  30. },
  31. {
  32. field: 'meta.title',
  33. label: t('menu.menuName')
  34. },
  35. {
  36. field: 'meta.icon',
  37. label: t('menu.icon'),
  38. slots: {
  39. default: (data: any) => {
  40. const icon = data[0].row.meta.icon
  41. if (icon) {
  42. return (
  43. <>
  44. <Icon icon={icon} />
  45. </>
  46. )
  47. } else {
  48. return null
  49. }
  50. }
  51. }
  52. },
  53. {
  54. field: 'meta.permission',
  55. label: t('menu.permission'),
  56. slots: {
  57. default: (data: any) => {
  58. const permission = data[0].row.meta.permission
  59. return permission ? <>{permission.join(', ')}</> : null
  60. }
  61. }
  62. },
  63. {
  64. field: 'component',
  65. label: t('menu.component'),
  66. slots: {
  67. default: (data: any) => {
  68. const component = data[0].row.component
  69. return <>{component === '#' ? '顶级目录' : component === '##' ? '子目录' : component}</>
  70. }
  71. }
  72. },
  73. {
  74. field: 'path',
  75. label: t('menu.path')
  76. },
  77. {
  78. field: 'status',
  79. label: t('menu.status'),
  80. slots: {
  81. default: (data: any) => {
  82. return (
  83. <>
  84. <ElTag type={data[0].row.status === 0 ? 'danger' : 'success'}>
  85. {data[0].row.status === 1 ? t('userDemo.enable') : t('userDemo.disable')}
  86. </ElTag>
  87. </>
  88. )
  89. }
  90. }
  91. },
  92. {
  93. field: 'action',
  94. label: t('userDemo.action'),
  95. width: 240,
  96. slots: {
  97. default: (data: any) => {
  98. const row = data[0].row
  99. return (
  100. <>
  101. <ElButton type="primary" onClick={() => action(row, 'edit')}>
  102. {t('exampleDemo.edit')}
  103. </ElButton>
  104. <ElButton type="danger">{t('exampleDemo.del')}</ElButton>
  105. </>
  106. )
  107. }
  108. }
  109. }
  110. ])
  111. const searchSchema = reactive<FormSchema[]>([
  112. {
  113. field: 'meta.title',
  114. label: t('menu.menuName'),
  115. component: 'Input'
  116. }
  117. ])
  118. const searchParams = ref({})
  119. const setSearchParams = (data: any) => {
  120. searchParams.value = data
  121. getList()
  122. }
  123. const dialogVisible = ref(false)
  124. const dialogTitle = ref('')
  125. const currentRow = ref()
  126. const actionType = ref('')
  127. const writeRef = ref<ComponentRef<typeof Write>>()
  128. const saveLoading = ref(false)
  129. const action = (row: any, type: string) => {
  130. dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail')
  131. actionType.value = type
  132. currentRow.value = row
  133. dialogVisible.value = true
  134. }
  135. const AddAction = () => {
  136. dialogTitle.value = t('exampleDemo.add')
  137. currentRow.value = undefined
  138. dialogVisible.value = true
  139. actionType.value = ''
  140. }
  141. const save = async () => {
  142. const write = unref(writeRef)
  143. const formData = await write?.submit()
  144. if (formData) {
  145. saveLoading.value = true
  146. setTimeout(() => {
  147. saveLoading.value = false
  148. dialogVisible.value = false
  149. }, 1000)
  150. }
  151. }
  152. </script>
  153. <template>
  154. <ContentWrap>
  155. <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
  156. <div class="mb-10px">
  157. <ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
  158. </div>
  159. <Table
  160. :columns="tableColumns"
  161. default-expand-all
  162. node-key="id"
  163. :data="dataList"
  164. :loading="loading"
  165. @register="tableRegister"
  166. />
  167. </ContentWrap>
  168. <Dialog v-model="dialogVisible" :title="dialogTitle">
  169. <Write v-if="actionType !== 'detail'" ref="writeRef" :current-row="currentRow" />
  170. <template #footer>
  171. <ElButton v-if="actionType !== 'detail'" type="primary" :loading="saveLoading" @click="save">
  172. {{ t('exampleDemo.save') }}
  173. </ElButton>
  174. <ElButton @click="dialogVisible = false">{{ t('dialogDemo.close') }}</ElButton>
  175. </template>
  176. </Dialog>
  177. </template>