123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- <template>
- <hc-new-card>
- <template #header>
- <div class="w-40">
- <el-select v-model="searchForm.sysId" filterable clearable block placeholder="选择所属系统">
- <el-option v-for="item in clinets" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </div>
- <div class="ml-3 w-60">
- <hc-search-input v-model="searchForm.name" placeholder="请输入菜单名称" @search="searchClick" />
- </div>
- </template>
- <template #extra>
- <el-button hc-btn type="primary" @click="addClick">新增</el-button>
- <el-button hc-btn type="danger" @click="delClick">删除</el-button>
- </template>
- <hc-table
- ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading"
- :is-index="false" is-new is-check :check-style="{ width: 29 }" lazy :load="tableLoad"
- @selection-change="tableCheckChange"
- >
- <template #sysId="{ row }">
- {{ getSystemNmae(row.sysId) }}
- </template>
- <template #category="{ row }">
- {{ row.category === 1 ? '菜单' : '按钮' }}
- </template>
- <template #action="{ row }">
- <el-link type="warning" @click="editRowClick(row)">修改</el-link>
- <el-link type="success" @click="addRowClick(row)">新增子项</el-link>
- <el-link type="primary" @click="copyRowClick(row)">复制</el-link>
- <el-link type="danger" @click="delRowClick(row)">删除</el-link>
- </template>
- </hc-table>
- <!-- 新增/修改 菜单 -->
- <hc-new-dialog v-model="isDialogShow" widths="800px" is-footer-center :title="iconDialogTitle" @close="dialogClose">
- <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="top" label-width="auto">
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="菜单名称:" prop="name">
- <el-input v-model="formModel.name" clearable />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="路由地址:" prop="path">
- <el-input v-model="formModel.path" clearable />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="菜单编号:" prop="code">
- <el-input v-model="formModel.code" clearable />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="菜单图标:">
- <el-input v-model="formModel.source" clearable>
- <template #append>
- <el-button @click="isIconShow = true">选择图标</el-button>
- </template>
- </el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="所属系统:" prop="sysId">
- <el-select v-model="formModel.sysId" placeholder="选择所属系统" filterable clearable block>
- <el-option v-for="item in clinets" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="上级菜单:">
- <el-tree-select
- v-model="formModel.parentId" placeholder="选择上级菜单"
- :data="levelMenu" :props="levelMenuProps" clearable filterable check-strictly block :render-after-expand="false"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="菜单类型:" prop="category">
- <div class="form-item-div">
- <el-radio-group v-model="formModel.category">
- <el-radio :label="1">菜单</el-radio>
- <el-radio :label="2">按钮</el-radio>
- </el-radio-group>
- </div>
- </el-form-item>
- </el-col>
- <el-col v-if="formModel.category === 2" :span="8">
- <el-form-item label="按钮是否显示:" prop="isShowButton">
- <div class="form-item-div">
- <el-radio-group v-model="formModel.isShowButton">
- <el-radio :label="2">否</el-radio>
- <el-radio :label="1">是</el-radio>
- </el-radio-group>
- </div>
- </el-form-item>
- </el-col>
- <el-col v-if="formModel.category === 1" :span="8">
- <el-form-item label="是否外层:" prop="isLayout">
- <div class="form-item-div">
- <el-radio-group v-model="formModel.isLayout">
- <el-radio :label="1">否</el-radio>
- <el-radio :label="2">是</el-radio>
- </el-radio-group>
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="是否新窗口:" prop="isOpen">
- <div class="form-item-div">
- <el-radio-group v-model="formModel.isOpen">
- <el-radio :label="1">否</el-radio>
- <el-radio :label="2">是</el-radio>
- </el-radio-group>
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="菜单排序:" prop="sort">
- <el-input-number v-model="formModel.sort" :min="1" block controls-position="right" />
- </el-form-item>
- </el-col>
- <el-col :span="16">
- <el-form-item label="按钮提示语:">
- <el-input v-model="formModel.textInfo" clearable :disabled="formModel.category === 1" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="菜单备注:">
- <el-input v-model="formModel.remark" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item>
- <template #label>
- <div class="hc-form-item-label">
- <div class="title-content">
- <span class="title">菜单备注:</span>
- <span content="text">(只能上传MP4格式,且不能用QQ录屏,推荐使用win10自带录屏录制,文件大小限制50兆)</span>
- </div>
- <div class="right-content">
- <el-link type="warning" @click="formModel.videoUrl = ''">清除</el-link>
- </div>
- </div>
- </template>
- <hc-form-upload :src="formModel.videoUrl" :num="1" @upload="videoUpload" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="文档信息:">
- <template #label>
- <div class="hc-form-item-label">
- <div class="title-content">文档信息:</div>
- <div class="right-content">
- <el-link type="warning" @click="formModel.excelUrl = ''">清除</el-link>
- </div>
- </div>
- </template>
- <hc-form-upload :src="formModel.excelUrl" :num="1" @upload="excelUpload" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <el-button hc-btn @click="dialogClose">取消</el-button>
- <el-button hc-btn type="primary" :loading="submitLoading" @click="dialogSubmit">提交</el-button>
- </template>
- </hc-new-dialog>
- <!-- 图标选择 -->
- <hc-menu-icon v-model="isIconShow" @finish="menuIconFinish" />
- <!-- 上传文件 -->
- <hc-upload-file ref="uploadRef" :echo-params="uploadParams" :options="uploadOptions" @success="uploadSuccess" />
- </hc-new-card>
- </template>
- <script setup>
- import { nextTick, onActivated, ref } from 'vue'
- import { useRoute, useRouter } from 'vue-router'
- import { arrToId, formValidate, getArrValue, getObjValue } from 'js-fast-way'
- import { delMessage, reloadPage } from '~uti/tools'
- import { getClinetAll } from '~api/other'
- import { getHeader } from 'hc-vue3-ui'
- import mainApi from '~api/system/menu'
- //初始组合式
- const router = useRouter()
- const useRoutes = useRoute()
- //激活
- onActivated(() => {
- //获取参数
- const { sysId, name } = getObjValue(useRoutes.query)
- searchForm.value = { sysId: sysId, name: name }
- //获取数据
- getClinetAllApi()
- getTableData()
- getLevelMenuData()
- })
- //获取所有系统
- const clinets = ref([])
- const getClinetAllApi = async () => {
- const { data } = await getClinetAll()
- clinets.value = getArrValue(data)
- }
- //获取系统名称
- const getSystemNmae = (id) => {
- const item = clinets.value.find((item) => item.id === id)
- return item ? item.name : ''
- }
- //搜索表单
- const searchForm = ref({
- sysId: null, name: null,
- })
- //搜索
- const searchClick = () => {
- router.push({
- name: 'menu',
- query: searchForm.value,
- })
- getTableData()
- }
- //表格数据
- const tableRef = ref(null)
- const tableColumn = ref([
- { key: 'name', name: '菜单名称' },
- { key: 'sysId', name: '所属系统' },
- { key: 'path', name: '路由地址' },
- { key: 'code', name: '菜单编号' },
- { key: 'category', name: '菜单类型', width: 90, align: 'center' },
- { key: 'sort', name: '排序', width: 80, align: 'center' },
- { key: 'action', name: '操作', width: 200, align: 'center' },
- ])
- //获取表格数据
- const tableLoading = ref(false)
- const tableData = ref([{}])
- const getTableData = async () => {
- tableData.value = []
- tableLoading.value = true
- const { data } = await mainApi.getLazyList({
- ...searchForm.value,
- parentId: 0,
- })
- tableData.value = getArrValue(data)
- tableLoading.value = false
- }
- //懒加载表格
- const tableLoad = async (row, node, resolve) => {
- const { data } = await mainApi.getLazyList({
- ...searchForm.value,
- parentId: row.id,
- })
- resolve(getArrValue(data))
- }
- //表格被选择
- const tableCheckKeys = ref([])
- const tableCheckChange = (rows) => {
- tableCheckKeys.value = rows
- }
- //上级菜单
- const levelMenuProps = {
- label: 'title',
- }
- const levelMenu = ref([])
- const getLevelMenuData = async () => {
- const { data } = await mainApi.getMenuTree()
- levelMenu.value = getArrValue(data)
- }
- //新增/修改 弹窗
- const isDialogShow = ref(false)
- const iconDialogTitle = ref('')
- //菜单表单
- const formRef = ref(null)
- const formModel = ref({})
- const formRules = {
- name: {
- required: true,
- trigger: 'blur',
- message: '请输入菜单名称',
- },
- path: {
- required: true,
- trigger: 'blur',
- message: '请输入路由地址',
- },
- code: {
- required: true,
- trigger: 'blur',
- message: '请输入菜单编号',
- },
- sysId: {
- required: true,
- trigger: 'blur',
- message: '请选择所属系统',
- },
- category: {
- required: true,
- trigger: 'blur',
- message: '请选择菜单类型',
- },
- isShowButton: {
- required: true,
- trigger: 'blur',
- message: '请选择按钮是否显示',
- },
- isLayout: {
- required: true,
- trigger: 'blur',
- message: '请选择是否外层',
- },
- isOpen: {
- required: true,
- trigger: 'blur',
- message: '请选择是否新窗口',
- },
- sort: {
- required: true,
- trigger: 'blur',
- message: '请输入菜单排序',
- },
- }
- //图标选择
- const isIconShow = ref(false)
- const menuIconFinish = (icon) => {
- formModel.value.source = icon
- isIconShow.value = false
- }
- //新增菜单
- const addClick = () => {
- iconDialogTitle.value = '新增菜单'
- formModel.value = {
- category: 1, isOpen: 1, isLayout: 1, isShowButton: 1,
- sort: 1, sysId: searchForm.value.sysId ?? null, parentId: null,
- }
- //显示表单弹窗
- nextTick(() => {
- isDialogShow.value = true
- })
- }
- //修改菜单
- const editRowClick = (row) => {
- formModel.value = {}
- iconDialogTitle.value = '修改菜单'
- formModel.value = { ...row }
- //显示表单弹窗
- nextTick(() => {
- isDialogShow.value = true
- })
- }
- //新增子项
- const addRowClick = (row) => {
- iconDialogTitle.value = '新增子菜单'
- formModel.value = {
- name: row.name, path: row.path, code: row.code, source: row.source,
- sysId: row.sysId, parentId: row.id,
- category: 1, isOpen: 1, isLayout: 1, isShowButton: 1, sort: 1,
- }
- //显示表单弹窗
- nextTick(() => {
- isDialogShow.value = true
- })
- }
- //复制菜单
- const copyRowClick = (row) => {
- iconDialogTitle.value = '复制菜单'
- formModel.value = {
- ...row,
- id: null,
- sort: row.sort + 1,
- }
- //显示表单弹窗
- nextTick(() => {
- isDialogShow.value = true
- })
- }
- //删除菜单
- const delRowClick = (row) => {
- delMessage(async () => {
- const { code, msg } = await mainApi.del(row.id)
- if (code === 200) {
- window.$message.success('删除成功')
- reloadPage()
- } else {
- window.$message.error(msg ?? '删除失败')
- }
- })
- }
- //批量删除菜单
- const delClick = () => {
- const rows = tableCheckKeys.value
- if (rows.length <= 0) {
- window.$message.warning('请选择要删除的菜单')
- return false
- }
- //确认删除菜单
- delMessage(async () => {
- const ids = arrToId(rows)
- const { code, msg } = await mainApi.del(ids)
- if (code === 200) {
- window.$message.success('删除成功')
- reloadPage()
- } else {
- window.$message.error(msg ?? '删除失败')
- }
- })
- }
- //上传文件
- const uploadRef = ref(null)
- const uploadParams = ref({})
- const uploadOptions = ref({
- url: '/api/blade-resource/oss/endpoint/put-file2',
- headers: getHeader(),
- multiple: false,
- })
- //上传视频
- const videoUpload = () => {
- uploadParams.value = { type: '视频文件' }
- uploadOptions.value.accept = 'video/mp4'
- uploadOptions.value.accept_tip = '只能上传MP4格式,且不能用QQ录屏,推荐使用win10自带录屏录制,文件大小限制50兆'
- uploadOptions.value.size = 50
- nextTick(() => {
- uploadRef.value?.selectFile()
- })
- }
- //上传文档
- const excelUpload = () => {
- uploadParams.value = { type: '文档文件' }
- uploadOptions.value.accept = null
- uploadOptions.value.accept_tip = null
- uploadOptions.value.size = null
- nextTick(() => {
- uploadRef.value?.selectFile()
- })
- }
- // 文件上传成功的回调
- const uploadSuccess = ({ echoParams, resData }) => {
- if (echoParams.type === '视频文件') {
- formModel.value.videoUrl = resData
- } else if (echoParams.type === '文档文件') {
- formModel.value.excelUrl = resData
- }
- //关闭弹窗
- uploadRef.value?.setModalShow(false)
- }
- //提交表单
- const submitLoading = ref(false)
- const dialogSubmit = async () => {
- const formRes = await formValidate(formRef.value)
- if (!formRes) return false
- submitLoading.value = true
- //处理数据
- const form = formModel.value
- form.parentId = form.parentId ?? 0
- form.alias = form.alias ?? form.code
- //发起请求
- const { error, code, msg } = await mainApi.submit(form)
- submitLoading.value = false
- if (!error && code === 200) {
- dialogClose()
- window?.$message?.success('操作成功')
- reloadPage()
- } else {
- window?.$message?.error(msg ?? '操作失败')
- }
- }
- //关闭弹窗
- const dialogClose = () => {
- isDialogShow.value = false
- submitLoading.value = false
- formModel.value = {}
- }
- </script>
|