menu.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template>
  2. <HcCard>
  3. <template #header>
  4. <div class="w-64">
  5. <el-input v-model="searchForm.name" size="large" placeholder="请输入菜单名称搜索" clearable />
  6. </div>
  7. <div class="ml-3">
  8. <el-button type="primary" size="large" @click="getTableData">
  9. <HcIcon name="search-2" />
  10. <span>搜索</span>
  11. </el-button>
  12. </div>
  13. </template>
  14. <template #extra>
  15. <el-button v-auth-btn="['system_menu_add_btn']" type="primary" size="large" @click="addMenu">
  16. <HcIcon name="add" />
  17. <span>新增</span>
  18. </el-button>
  19. <el-button v-auth-btn="['system_menu_del_btn']" type="danger" size="large" :disabled="!tableCheckedKeys" @click="deleteClick">
  20. <HcIcon name="delete-bin-2" />
  21. <span>删除</span>
  22. </el-button>
  23. </template>
  24. <HcTable
  25. ui="no-border" border has-children="hasChildren1" :is-index="false" is-check
  26. :column="tableColumn" :datas="tableData" @selection-change="tableSelectionChange"
  27. >
  28. <template #name="{ row }">
  29. <i v-if="row.source" :class="[`ri-${row?.source}`]" class="hc-icon-i table-menu-icon" />
  30. <span>{{ row.name }}</span>
  31. </template>
  32. <template #category="{ row }">
  33. <span v-if="row.category === 1">菜单</span>
  34. <span v-if="row.category === 2">按钮</span>
  35. </template>
  36. <template #action="{ row }">
  37. <el-button v-auth-btn="['system_menu_edit_btn']" size="small" type="primary" @click="eidtMenu(row)">
  38. 编辑
  39. </el-button>
  40. <el-button v-auth-btn="['system_menu_add_children_btn']" size="small" type="success" @click="addChildren(row)">
  41. 新增子项
  42. </el-button>
  43. <el-button v-auth-btn="['system_menu_copy_btn']" size="small" type="warning" @click="copyChildren(row)">
  44. 复制
  45. </el-button>
  46. </template>
  47. </HcTable>
  48. <!-- 菜单新增编辑 -->
  49. <HcDialog
  50. bg-color="#ffffff" is-to-body widths="60rem" :title="isCopy ? '复制菜单数据' : formModel.id ? '编辑菜单' : '修改菜单'"
  51. :show="menuDataModal" @save="menuDataModalSave" @close="menuDataModalClose"
  52. >
  53. <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="left" label-width="auto" size="large">
  54. <el-row :gutter="20">
  55. <el-col :span="12">
  56. <el-form-item label="菜单名称:" prop="name">
  57. <el-input v-model="formModel.name" placeholder="六字以内的名称" />
  58. </el-form-item>
  59. <el-form-item label="路由地址:" prop="path">
  60. <el-input v-model="formModel.path" placeholder="url上显示的地址" />
  61. </el-form-item>
  62. <el-form-item label="菜单编号:" prop="code">
  63. <el-input v-model="formModel.code" placeholder="路由中的跳转name" />
  64. </el-form-item>
  65. <el-form-item label="菜单备注:">
  66. <el-input v-model="formModel.remark" />
  67. </el-form-item>
  68. </el-col>
  69. <el-col :span="12">
  70. <el-form-item label="上级菜单:">
  71. <el-cascader v-model="formModel.parentId" :options="tableData" :props="topMenuoptions" clearable />
  72. </el-form-item>
  73. <el-form-item label="菜单图标:">
  74. <el-input v-model="formModel.source" placeholder="图标库为 ">
  75. <template #append>
  76. <a href="https://remixicon.cn/" target="_blank">图标库</a>
  77. </template>
  78. </el-input>
  79. </el-form-item>
  80. <el-form-item label="菜单排序:">
  81. <el-input-number v-model="formModel.sort" :min="1" :max="10" controls-position="right" />
  82. </el-form-item>
  83. <el-form-item label="菜单类型:">
  84. <el-radio-group v-model="formModel.category">
  85. <el-radio :label="1">
  86. 菜单
  87. </el-radio>
  88. <el-radio :label="2" class="ml-6">
  89. 按钮
  90. </el-radio>
  91. </el-radio-group>
  92. </el-form-item>
  93. </el-col>
  94. </el-row>
  95. </el-form>
  96. </HcDialog>
  97. </HcCard>
  98. </template>
  99. <script setup>
  100. import { onActivated, ref } from 'vue'
  101. import mainApi from '~api/system/menu'
  102. import { arrToId, formValidate, getArrValue } from 'js-fast-way'
  103. import config from '~src/config/index'
  104. import { delMessageV2 } from '~com/message/index.js'
  105. //页面被激活时
  106. onActivated(() => {
  107. getTableData()
  108. })
  109. //菜单数据
  110. const searchForm = ref({ name: '', parentId: '' })
  111. const tableColumn = [
  112. { key: 'name', name: '菜单名称', minWidth: 260 },
  113. { key: 'code', name: '菜单编号', width: 240 },
  114. { key: 'path', name: '路由地址', minWidth: 220 },
  115. { key: 'category', name: '菜单类型', width: 90, align: 'center' },
  116. { key: 'sort', name: '排序', width: 80, align: 'center' },
  117. { key: 'remark', name: '菜单备注', minWidth: 200 },
  118. { key: 'action', name: '操作', width: 240, fixed: 'right', align: 'center' },
  119. ]
  120. const tableData = ref([])
  121. const getTableData = async () => {
  122. const { error, code, data } = await mainApi.lazyList(searchForm.value)
  123. if (!error && code === 200) {
  124. tableData.value = getArrValue(data)
  125. } else {
  126. tableData.value = []
  127. }
  128. }
  129. //多选
  130. const tableCheckedKeys = ref('')
  131. const tableSelectionChange = (rows) => {
  132. tableCheckedKeys.value = arrToId(rows)
  133. }
  134. //删除菜单
  135. const deleteClick = () => {
  136. if (tableCheckedKeys.value) {
  137. delMessageV2(async (action, instance, done) => {
  138. if (action === 'confirm') {
  139. instance.confirmButtonLoading = true
  140. deleteApi(tableCheckedKeys.value)
  141. instance.confirmButtonLoading = false
  142. done()
  143. } else {
  144. done()
  145. }
  146. })
  147. } else {
  148. window.$message.warning('请选择要删除的菜单')
  149. }
  150. }
  151. //删除请求
  152. const deleteApi = async (ids) => {
  153. const { error, code, msg } = await mainApi.remove(ids)
  154. if (!error && code === 200) {
  155. window.$message.success('删除成功')
  156. getTableData().then()
  157. } else {
  158. window.$message.success(msg)
  159. }
  160. }
  161. //菜单数据弹窗
  162. const menuDataModal = ref(false)
  163. const formRef = ref(null)
  164. const formModel = ref({ category: 1 })
  165. const formRules = {
  166. name: { required: true, trigger: 'blur', message: '请输入菜单名称' },
  167. path: { required: true, trigger: 'blur', message: '请输入路由地址' },
  168. code: { required: true, trigger: 'blur', message: '请输入菜单编号' },
  169. }
  170. const topMenuoptions = {
  171. checkStrictly: true,
  172. emitPath: false,
  173. value: 'id',
  174. label: 'name',
  175. }
  176. //新增菜单
  177. const addMenu = () => {
  178. formModel.value = {
  179. sysId: config.sysId,
  180. isOpen: 1,
  181. isLayout: 1,
  182. category: 1,
  183. parentId: 0,
  184. sort: 1,
  185. }
  186. isCopy.value = false
  187. menuDataModal.value = true
  188. }
  189. //编辑菜单
  190. const eidtMenu = (row) => {
  191. formModel.value = {
  192. ...row,
  193. children: null,
  194. }
  195. isCopy.value = false
  196. menuDataModal.value = true
  197. }
  198. //新增子级菜单
  199. const addChildren = (row) => {
  200. formModel.value = {
  201. sysId: config.sysId,
  202. isOpen: 1,
  203. isLayout: 1,
  204. category: 1,
  205. parentId: row.id,
  206. sort: 1,
  207. }
  208. isCopy.value = false
  209. menuDataModal.value = true
  210. }
  211. //复制菜单
  212. const isCopy = ref(false)
  213. const copyChildren = (row) => {
  214. formModel.value = {
  215. ...row,
  216. children: null,
  217. id: '',
  218. }
  219. isCopy.value = true
  220. menuDataModal.value = true
  221. }
  222. //提交保存
  223. const menuDataModalSave = async () => {
  224. const isForm = await formValidate(formRef.value)
  225. if (isForm) {
  226. const form = formModel.value
  227. const { error, code, msg } = await mainApi.submit({
  228. ...form,
  229. alias: form.code,
  230. })
  231. if (!error && code === 200) {
  232. window.$message.success('保存成功')
  233. menuDataModal.value = false
  234. getTableData().then()
  235. } else {
  236. window.$message.error(msg)
  237. }
  238. }
  239. }
  240. //弹窗关闭
  241. const menuDataModalClose = () => {
  242. menuDataModal.value = false
  243. isCopy.value = false
  244. formModel.value = {}
  245. }
  246. </script>
  247. <style>
  248. .table-menu-icon {
  249. margin-right: 5px;
  250. }
  251. </style>