ProTable.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <script setup lang="ts">
  2. import { ElMessage, ElMessageBox, type FormProps } from 'element-plus'
  3. import type { PropType } from 'vue'
  4. interface column {
  5. label?: string
  6. value: string
  7. name: string
  8. formType: string
  9. placeholder: string
  10. options: Array<any>
  11. rules: any
  12. search: boolean
  13. width: string | number
  14. type: string
  15. span: number
  16. }
  17. interface CRUD {
  18. create: Function
  19. update: Function
  20. delete: Function
  21. getList: Function
  22. getRecord: Function
  23. }
  24. const props = defineProps({
  25. crud: Object as PropType<CRUD>,
  26. pageSize: {
  27. type: Number,
  28. default: 10
  29. },
  30. columns: {
  31. type: Array as PropType<column[]>,
  32. default: () => []
  33. },
  34. selection: {
  35. type: Boolean,
  36. default: true
  37. },
  38. form: Object as PropType<FormProps>,
  39. formItem: Object,
  40. formComp: Object
  41. })
  42. // ============== 查询部分开始 ===============
  43. const query = ref<any>({})
  44. const searchList = computed(() => props.columns.filter(item => item.search))
  45. const handleQuery = () => {
  46. curPage.value = 1
  47. getTableData()
  48. }
  49. const handleReset = () => {
  50. query.value = {}
  51. }
  52. // ============== 查询部分结束 ===============
  53. // ============== 表格部分开始 ===============
  54. const tableData = ref([])
  55. const total = ref(0)
  56. const curPage = ref(1)
  57. const getTableData = () => {
  58. props.crud
  59. ?.getList({
  60. ...query.value,
  61. pageSize: props.pageSize,
  62. page: curPage.value
  63. })
  64. .then((res: any) => {
  65. tableData.value = res.data
  66. total.value = res.total
  67. })
  68. }
  69. getTableData()
  70. const pageChange = () => {
  71. getTableData()
  72. }
  73. const multipleSelection = ref<any[]>([])
  74. const handleSelectionChange = (columns: any[]) => {
  75. multipleSelection.value = columns
  76. }
  77. // ============== 表格部分结束 ===============
  78. // ============== crud部分开始 ===============
  79. const handleCreate = () => {
  80. dialogTitle.value = '新增'
  81. dialogVisible.value = true
  82. }
  83. const handleUpdate = (row: any) => {
  84. dialogTitle.value = '编辑'
  85. dialogVisible.value = true
  86. if (props.crud?.getRecord) {
  87. props.crud.getRecord({ id: row.id }).then((res: any) => {
  88. formData.value = res.data
  89. })
  90. } else {
  91. formData.value = row
  92. }
  93. }
  94. const handleDelete = (id: string | number) => {
  95. ElMessageBox.confirm('您确定要删除该项吗', '提示', {
  96. type: 'warning'
  97. }).then(async () => {
  98. const res = await props.crud?.delete(id)
  99. if (res.code === 0) {
  100. ElMessage({
  101. type: 'success',
  102. message: '删除成功'
  103. })
  104. }
  105. })
  106. }
  107. const handlePatchDelete = () => {}
  108. // ============== crud部分结束 ===============
  109. // ============== 表单部分开始 ===============
  110. const formConfig: any = ref({
  111. labelWidth: '100px',
  112. labelPosition: 'top',
  113. size: 'large',
  114. ...props.form
  115. })
  116. const dialogTitle = ref('新增')
  117. const dialogVisible = ref(false)
  118. const closeDialog = () => {
  119. dialogVisible.value = false
  120. formData.value = {}
  121. }
  122. const formData = ref<any>({})
  123. const formRef = ref()
  124. const formList = computed(() => props.columns.filter(item => item.formType))
  125. const placeholder = (item: column) => {
  126. if (['select'].includes(item.formType)) {
  127. return '请选择' + item.label
  128. } else {
  129. return '请输入' + item.label
  130. }
  131. }
  132. formList.value.forEach(item => {
  133. formData.value[item.name] = item.value
  134. })
  135. const submit = () => {
  136. let res, message
  137. formRef.value.validate(async (valid: boolean) => {
  138. if (valid) {
  139. if (formData.value.id) {
  140. res = props.crud?.update(formData.value)
  141. message = '新增成功'
  142. } else {
  143. res = props.crud?.create(formData.value)
  144. message = '修改成功'
  145. }
  146. if (res.code === 0) {
  147. ElMessage({
  148. type: 'success',
  149. message
  150. })
  151. closeDialog()
  152. }
  153. }
  154. })
  155. }
  156. // ============== 表单部分结束 ===============
  157. </script>
  158. <template>
  159. <div class="flex flex-col" style="height: calc(100vh - 60px - var(--main-padding) * 2)">
  160. <el-card class="mb-4" shadow="never">
  161. <el-form :inline="true">
  162. <el-form-item :label="item.label" v-for="item in searchList">
  163. <component
  164. :is="'el-' + item.formType"
  165. v-model="query[item.name]"
  166. :placeholder="item.placeholder || placeholder(item)"
  167. >
  168. <template v-if="item.formType === 'radio-group'">
  169. <el-radio :label="option.label" v-for="option in item.options">{{ option.value }}</el-radio>
  170. </template>
  171. </component>
  172. </el-form-item>
  173. <el-form-item>
  174. <el-button type="primary" @click="handleQuery">查询</el-button>
  175. <el-button @click="handleReset">重置</el-button>
  176. </el-form-item>
  177. </el-form>
  178. </el-card>
  179. <el-card class="h-full flex-grow-1" :body-style="{ height: '100%' }" shadow="never">
  180. <div class="flex flex-col h-full">
  181. <div class="flex justify-between mb-20px">
  182. <div>
  183. <el-button type="primary" @click="handleCreate">新增</el-button>
  184. <el-button type="danger" @click="handlePatchDelete" :disabled="!multipleSelection.length" v-if="selection">
  185. 删除
  186. </el-button>
  187. </div>
  188. </div>
  189. <el-table class="flex-grow-1 h-full" :data="tableData" @selection-change="handleSelectionChange">
  190. <el-table-column type="selection" width="50" v-if="selection"></el-table-column>
  191. <slot></slot>
  192. <el-table-column fixed="right" label="操作" width="120">
  193. <template #default="{ row }">
  194. <el-button link type="primary" size="small" @click="handleUpdate(row)">编辑</el-button>
  195. <el-button link type="danger" size="small" @click="handleDelete(row.id)">删除</el-button>
  196. </template>
  197. </el-table-column>
  198. </el-table>
  199. <div class="flex justify-end shrink-0">
  200. <el-pagination
  201. background
  202. layout="prev, pager, next"
  203. :page-size="pageSize"
  204. :total="total"
  205. @current-change="pageChange"
  206. class="mt-4"
  207. />
  208. </div>
  209. </div>
  210. </el-card>
  211. <el-dialog
  212. draggable
  213. :title="dialogTitle"
  214. v-model="dialogVisible"
  215. width="1000px"
  216. @close="closeDialog"
  217. :close-on-click-modal="false"
  218. >
  219. <el-form :model="formData" ref="formRef" v-bind="formConfig" class="form">
  220. <el-row :gutter="20">
  221. <el-col :span="item.span || 12" v-for="item in formList">
  222. <el-form-item :label="item.label" :rules="item.rules" :prop="item.name">
  223. <component
  224. :is="'el-' + item.formType"
  225. v-model="formData[item.name]"
  226. v-bind="formComp"
  227. :placeholder="item.placeholder || placeholder(item)"
  228. >
  229. <template v-if="item.formType === 'radio-group'">
  230. <el-radio :label="option.label" v-for="option in item.options">{{ option.value }}</el-radio>
  231. </template>
  232. <template v-else-if="item.formType === 'select'">
  233. <el-option :label="option.label" :value="option.value" v-for="option in item.options"></el-option>
  234. </template>
  235. </component>
  236. </el-form-item>
  237. </el-col>
  238. </el-row>
  239. </el-form>
  240. <template #footer>
  241. <el-button @click="dialogVisible = false">取消</el-button>
  242. <el-button type="primary" @click="submit">保存</el-button>
  243. </template>
  244. </el-dialog>
  245. </div>
  246. </template>
  247. <style scoped>
  248. :deep(.el-table th.el-table__cell) {
  249. background-color: #f5f7fa;
  250. color: rgb(31, 34, 37);
  251. }
  252. .form .el-select {
  253. width: 100%;
  254. }
  255. </style>