123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- <template>
- <CommonPage back :title="detail.title">
- <template #action>
- <n-space>
- <NButton type="tertiary" @click="handleTopMenuEdit">
- 编辑
- </NButton>
- <NButton type="primary" @click="handleSubAdd()">
- <i class="i-material-symbols:add mr-4 text-18" />
- 新增子菜单
- </NButton>
- </n-space>
- </template>
- <MeCrud ref="$table" v-model:query-items="queryItems" :scroll-x="1200" :columns="columns" :get-data="api.read">
- <MeQueryItem label="标题" :label-width="50">
- <n-input v-model:value="queryItems.title" type="text" placeholder="请输入标题名" clearable>
- <template #password-visible-icon />
- </n-input>
- </MeQueryItem>
- <MeQueryItem label="状态" :label-width="50">
- <n-select
- v-model:value="queryItems.enable" clearable :options="[
- { label: '启用', value: 1 },
- { label: '停用', value: 0 },
- ]"
- />
- </MeQueryItem>
- </MeCrud>
- <MeModal ref="modalRef" width="520px">
- <n-form ref="modalFormRef" label-placement="left" label-align="left" :label-width="95" :model="modalForm">
- <n-form-item
- label="名称" path="title" :rule="{
- required: true,
- message: '请输入名称',
- trigger: ['input', 'blur'],
- }"
- >
- <n-input v-model:value="modalForm.title" />
- </n-form-item>
- <n-form-item
- label="描述" path="description" :rule="{
- required: false,
- message: '请输入描述',
- trigger: ['input', 'blur'],
- }"
- >
- <n-input v-model:value="modalForm.description" type="textarea" />
- </n-form-item>
- <n-form-item v-if="modalForm.level !== 0" label="封面" path="cover">
- <n-upload
- :multiple="false"
- :default-upload="true"
- list-type="image-card"
- :custom-request="uploadCover"
- :max="1"
- :default-file-list="previewFileList"
- @preview="handlePreview"
- @remove="handleCoverRemove"
- />
- <n-modal
- v-model:show="showModal"
- preset="card"
- style="width: 600px"
- title=""
- >
- <img :src="previewImageUrl" style="width: 100%">
- </n-modal>
- </n-form-item>
- <n-form-item
- label="分类" path="categoryId" :rule="{
- required: modalForm.level === 0 ? false : true,
- type: 'number',
- trigger: ['change', 'blur'],
- message: '请输入分类',
- }"
- >
- <n-tree-select
- v-model:value="modalForm.categoryId"
- :options="allCategory"
- label-field="title"
- key-field="id"
- placeholder="根分类"
- clearable
- />
- </n-form-item>
- <n-form-item
- v-if="modalForm.level === 0"
- label="样式类型" path="styleType" :rule="{
- required: true,
- type: 'number',
- message: '请输入样式类型',
- trigger: ['input', 'blur'],
- }"
- >
- <n-select
- v-model:value="modalForm.styleType" :options="styleEnum" clearable filterable tag
- />
- </n-form-item>
- <n-form-item
- label="文章链接" path="articleId" :rule="{
- required: false,
- type: 'number',
- trigger: ['change', 'blur'],
- message: '请输入文章链接',
- }"
- >
- <n-select
- v-model:value="modalForm.articleId" :options="allArticle"
- clearable filterable tag
- />
- </n-form-item>
- <n-form-item
- v-if="modalForm.level === 0"
- label="一行显示数" path="grid"
- >
- <n-input-number v-model:value="modalForm.grid" style="width:100%" />
- </n-form-item>
- <n-form-item
- label="排序"
- path="order"
- :rule="{
- type: 'number',
- required: true,
- message: '此为必填项',
- trigger: ['blur', 'change'],
- }"
- >
- <n-input-number v-model:value="modalForm.order" />
- </n-form-item>
- <n-tabs type="line" animated>
- <template v-for="(lang, index) in langs" :key="lang">
- <n-tab-pane :name="lang" :tab="langLabel[lang]" :index="index">
- {{ lang }}
- <n-form-item
- label="文章名称" path="title" :rule="{
- required: true,
- message: '请输入文章名称',
- trigger: ['input', 'blur'],
- }"
- >
- <n-input v-model:value="modalForm.translations[index].title" />
- </n-form-item>
- </n-tab-pane>
- </template>
- </n-tabs>
- <n-form-item label="是否显示" path="isPublish">
- <NSwitch v-model:value="modalForm.isPublish">
- <template #checked>
- 启用
- </template>
- <template #unchecked>
- 停用
- </template>
- </NSwitch>
- </n-form-item>
- <n-form-item label="状态" path="enable">
- <NSwitch v-model:value="modalForm.enable">
- <template #checked>
- 启用
- </template>
- <template #unchecked>
- 停用
- </template>
- </NSwitch>
- </n-form-item>
- </n-form>
- </MeModal>
- </CommonPage>
- </template>
- <script setup>
- import { MeCrud, MeModal, MeQueryItem } from '@/components'
- import { CommonPage } from '@/components/index.js'
- import { useCrud } from '@/composables'
- import { useUserStore } from '@/store/index.js'
- import { formatDateTime } from '@/utils'
- import { styleEnum } from '@/utils/enum.js'
- import { initTranslations, langLabel, langs } from '@/utils/translations'
- import { NButton, NImage, NSwitch } from 'naive-ui'
- import { useRoute, useRouter } from 'vue-router'
- import articleApi from '../article/api'
- import categoryApi from '../category/api'
- import api from './api.js'
- const $table = ref(null)
- const router = useRouter()
- const { userId } = useUserStore()
- const previewFileList = ref([])
- const showModal = ref(false)
- const previewImageUrl = ref('')
- const allCategory = ref([])
- const allArticle = ref([])
- const route = useRoute()
- const detail = ref({
- title: '',
- id: null,
- })
- /** QueryBar筛选参数(可选) */
- const queryItems = ref({
- parentId: route.params.id,
- })
- const { modalRef, modalFormRef, modalAction, modalForm, handleAdd, handleDelete, handleEdit }
- = useCrud({
- name: '子菜单',
- doCreate: api.create,
- doDelete: api.delete,
- doUpdate: api.update,
- initForm: { enable: true, isPublish: true, order: 0 },
- refresh: (_, keepCurrentPage) => $table.value?.handleSearch(keepCurrentPage),
- })
- initTranslations(modalForm.value, ['title', 'remark'])
- async function getMenuDetail() {
- const { data } = await api.getOne(route.params.id)
- if (data) {
- console.log('data', data)
- detail.value = data
- }
- getAllType()
- }
- const columns = [
- { title: '标题名', key: 'title', width: '200' },
- { title: '分类', key: 'category.title' },
- {
- title: '封面图',
- key: 'cover',
- render: row => row.cover
- ? h(NImage, {
- src: row.cover,
- height: 60,
- width: 80,
- })
- : null,
- },
- {
- title: '创建时间',
- key: 'createTime',
- render: row => h('span', formatDateTime(row.createTime)),
- },
- {
- title: '状态',
- key: 'enable',
- render: row =>
- h(
- NSwitch,
- {
- size: 'small',
- rubberBand: false,
- value: row.enable,
- loading: !!row.enableLoading,
- disabled: row.code === 'SUPER_ADMIN',
- onUpdateValue: () => handleEnable(row),
- },
- {
- checked: () => '启用',
- unchecked: () => '停用',
- },
- ),
- },
- {
- title: '操作',
- key: 'actions',
- width: 200,
- align: 'center',
- fixed: 'right',
- render(row) {
- return [
- h(
- NButton,
- {
- size: 'small',
- type: 'primary',
- style: 'margin-left: 12px;',
- disabled: row.code === 'SUPER_ADMIN',
- onClick: () => handleFormEdit(row),
- },
- {
- default: () => '编辑',
- icon: () => h('i', { class: 'i-material-symbols:edit-outline text-14' }),
- },
- ),
- h(
- NButton,
- {
- size: 'small',
- type: 'error',
- style: 'margin-left: 12px;',
- disabled: row.code === 'SUPER_ADMIN',
- onClick: () => handleDelete(row.id),
- },
- {
- default: () => '删除',
- icon: () => h('i', { class: 'i-material-symbols:delete-outline text-14' }),
- },
- ),
- ]
- },
- },
- ]
- async function handleEnable(row) {
- row.enableLoading = true
- try {
- await api.update({ id: row.id, enable: !row.enable })
- row.enableLoading = false
- $message.success('操作成功')
- $table.value?.handleSearch()
- }
- catch (error) {
- console.error(error)
- row.enableLoading = false
- }
- }
- watchEffect(() => {
- if (userId) {
- modalForm.value.userId = userId
- if (modalForm.value.level !== 0) {
- modalForm.value.parentId = detail.value.id
- }
- }
- })
- onMounted(() => {
- $table.value?.handleSearch()
- getMenuDetail()
- })
- async function uploadCover({ file }) {
- const data = new FormData()
- data.append('file', file.file)
- const res = await api.uploadImage(data)
- modalForm.value.cover = res.data
- file.url = res.data
- file.thumbnailUrl = res.data
- previewFileList.value = [{
- id: '0',
- status: 'finished',
- url: res.data,
- }]
- }
- function handlePreview(file) {
- const { url } = file
- previewImageUrl.value = url
- showModal.value = true
- }
- async function handleFormEdit(data = {}) {
- modalForm.value = {
- ...data,
- userId,
- }
- console.log('handleFormEdit', modalForm.value)
- if (modalForm.value.cover) {
- previewFileList.value = [{
- id: '0',
- status: 'finished',
- url: modalForm.value.cover,
- }]
- }
- else {
- previewFileList.value = []
- }
- handleEdit(data)
- }
- function handleCoverRemove() {
- modalForm.value.cover = ''
- previewFileList.value = []
- previewImageUrl.value = ''
- }
- function handleSubAdd() {
- modalForm.value.level = 1
- modalForm.value.cover = ''
- previewFileList.value = []
- handleAdd({ level: 1, cover: '' })
- }
- function handleTopMenuEdit() {
- modalForm.value = {
- cover: '',
- ...detail.value,
- userId,
- level: 0,
- parentId: null,
- }
- handleEdit(modalForm.value, '编辑顶层菜单', () => {
- getMenuDetail()
- })
- }
- function getAllType() {
- categoryApi.getAll().then(({ data = [] }) => (allCategory.value = data))
- articleApi.getAll().then(({ data = [] }) => (allArticle.value = data.map(item => ({
- label: item.title,
- value: +item.id,
- }))))
- }
- </script>
|