ChannelManage.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <script setup lang="tsx">
  2. import {
  3. ElButton,
  4. ElSwitch,
  5. ElDrawer,
  6. ElForm,
  7. ElFormItem,
  8. ElInput,
  9. ElMessageBox,
  10. ElMessage
  11. } from 'element-plus'
  12. import { ContentWrap } from '@/components/ContentWrap'
  13. import { useI18n } from '@/hooks/web/useI18n'
  14. import { Table, TableColumn } from '@/components/Table'
  15. import { BaseButton } from '@/components/Button'
  16. import type { ChannelData } from '@/api/channel/types'
  17. import { ref, reactive } from 'vue'
  18. import { getChannelListApi, addChannelApi, editChannelApi, delChannelApi } from '@/api/channel'
  19. const { t } = useI18n()
  20. const columns: TableColumn[] = [
  21. {
  22. field: 'name',
  23. label: t('channel.name')
  24. },
  25. {
  26. field: 'code',
  27. label: t('channel.code')
  28. },
  29. {
  30. field: 'description',
  31. label: t('channel.description'),
  32. showOverflowTooltip: true
  33. },
  34. {
  35. field: 'status',
  36. label: t('channel.status'),
  37. slots: {
  38. default: (data) => {
  39. return (
  40. <ElSwitch
  41. modelValue={data.row.status}
  42. onUpdate:modelValue={(val) => updateStatus(data.row, val)}
  43. />
  44. )
  45. }
  46. }
  47. },
  48. {
  49. field: 'createTime',
  50. label: t('channel.createTime')
  51. },
  52. {
  53. field: 'action',
  54. label: t('channel.action'),
  55. width: 180,
  56. slots: {
  57. default: (data) => {
  58. return (
  59. <>
  60. <BaseButton type="primary" onClick={() => actionFn('edit', data.row)}>
  61. {t('channel.edit')}
  62. </BaseButton>
  63. <BaseButton type="danger" onClick={() => deleteFn(data.row)}>
  64. {t('channel.delete')}
  65. </BaseButton>
  66. </>
  67. )
  68. }
  69. }
  70. }
  71. ]
  72. const loading = ref(true)
  73. const channelList = ref<ChannelData[]>([])
  74. const drawer = ref(false)
  75. const drawerTitle = ref('')
  76. const searchName = ref('')
  77. const form = reactive({
  78. type: 'add',
  79. data: {
  80. id: '',
  81. name: '',
  82. code: '',
  83. description: '',
  84. status: true
  85. }
  86. })
  87. const formReset = () => {
  88. form.data.id = ''
  89. form.data.name = ''
  90. form.data.code = ''
  91. form.data.description = ''
  92. form.data.status = true
  93. }
  94. const getList = async () => {
  95. loading.value = true
  96. const res = await getChannelListApi({
  97. name: searchName.value || undefined,
  98. pageIndex: 1,
  99. pageSize: 100
  100. })
  101. .catch(() => ({}))
  102. .finally(() => {
  103. loading.value = false
  104. })
  105. if (res?.data) {
  106. channelList.value = res.data.list || []
  107. }
  108. }
  109. const updateStatus = async (row: ChannelData, val: boolean) => {
  110. if (!row.id) return
  111. await editChannelApi({ id: row.id, status: val })
  112. .then(() => {
  113. ElMessage.success(t('channel.updateSuccess'))
  114. row.status = val
  115. })
  116. .catch(() => {})
  117. }
  118. const actionFn = (type: 'add' | 'edit', row?: ChannelData) => {
  119. formReset()
  120. if (type === 'add') {
  121. form.type = 'add'
  122. drawerTitle.value = t('channel.add')
  123. } else if (row) {
  124. form.type = 'edit'
  125. drawerTitle.value = t('channel.edit')
  126. form.data.id = row.id!
  127. form.data.name = row.name
  128. form.data.code = row.code
  129. form.data.description = row.description || ''
  130. form.data.status = row.status !== false
  131. }
  132. drawer.value = true
  133. }
  134. const onSubmit = async () => {
  135. if (!form.data.name?.trim()) {
  136. ElMessage.warning(t('channel.nameRequired'))
  137. return
  138. }
  139. if (!form.data.code?.trim()) {
  140. ElMessage.warning(t('channel.codeRequired'))
  141. return
  142. }
  143. if (form.type === 'add') {
  144. await addChannelApi(form.data)
  145. .then(() => {
  146. ElMessage.success(t('channel.addSuccess'))
  147. drawer.value = false
  148. getList()
  149. })
  150. .catch(() => {})
  151. } else {
  152. await editChannelApi(form.data)
  153. .then(() => {
  154. ElMessage.success(t('channel.editSuccess'))
  155. drawer.value = false
  156. getList()
  157. })
  158. .catch(() => {})
  159. }
  160. }
  161. const deleteFn = (row: ChannelData) => {
  162. ElMessageBox.confirm(t('channel.deleteConfirm'), t('common.delWarning'), {
  163. confirmButtonText: t('common.delOk'),
  164. cancelButtonText: t('common.cancel'),
  165. type: 'warning'
  166. })
  167. .then(async () => {
  168. await delChannelApi([row.id!])
  169. ElMessage.success(t('channel.deleteSuccess'))
  170. getList()
  171. })
  172. .catch(() => {})
  173. }
  174. const onSearch = () => {
  175. getList()
  176. }
  177. const onReset = () => {
  178. searchName.value = ''
  179. getList()
  180. }
  181. getList()
  182. </script>
  183. <template>
  184. <ContentWrap>
  185. <div class="mb-4 flex flex-wrap items-center gap-3">
  186. <ElButton type="primary" @click="actionFn('add')">
  187. {{ t('channel.add') }}
  188. </ElButton>
  189. <div class="flex items-center gap-2">
  190. <el-input
  191. v-model="searchName"
  192. :placeholder="t('channel.searchPlaceholder')"
  193. clearable
  194. style="width: 200px"
  195. @keyup.enter="onSearch"
  196. />
  197. <ElButton type="primary" @click="onSearch">{{ t('common.query') }}</ElButton>
  198. <ElButton @click="onReset">{{ t('common.reset') }}</ElButton>
  199. </div>
  200. </div>
  201. </ContentWrap>
  202. <ContentWrap>
  203. <Table :columns="columns" :data="channelList" :loading="loading" row-key="id" />
  204. </ContentWrap>
  205. <ElDrawer v-model="drawer" direction="rtl" size="40%" :title="drawerTitle">
  206. <ElForm :model="form.data" label-width="auto" style="max-width: 500px">
  207. <ElFormItem :label="t('channel.name')" required>
  208. <ElInput v-model="form.data.name" :placeholder="t('channel.namePlaceholder')" />
  209. </ElFormItem>
  210. <ElFormItem :label="t('channel.code')" required>
  211. <ElInput
  212. v-model="form.data.code"
  213. :placeholder="t('channel.codePlaceholder')"
  214. :disabled="form.type === 'edit'"
  215. />
  216. </ElFormItem>
  217. <ElFormItem :label="t('channel.description')">
  218. <ElInput
  219. v-model="form.data.description"
  220. type="textarea"
  221. :rows="3"
  222. :placeholder="t('channel.descriptionPlaceholder')"
  223. />
  224. </ElFormItem>
  225. <ElFormItem :label="t('channel.status')">
  226. <ElSwitch v-model="form.data.status" />
  227. </ElFormItem>
  228. <ElFormItem>
  229. <ElButton type="primary" @click="onSubmit">{{ t('common.ok') }}</ElButton>
  230. <ElButton @click="drawer = false">{{ t('common.cancel') }}</ElButton>
  231. </ElFormItem>
  232. </ElForm>
  233. </ElDrawer>
  234. </template>