This commit is contained in:
2025-04-25 11:47:08 +08:00
parent f9381e74ed
commit dfb552b7ed
15 changed files with 488 additions and 114 deletions

View File

@@ -412,6 +412,14 @@ const admin = {
data: data data: data
}); });
}, },
getArticleCategoryList2: async (data) => {
const res = await request({
url: '/admin/articleCategory/getList',
method: Method.POST,
data: data
});
return {data: res.data.list};
},
addArticleCategory: async (data) => { addArticleCategory: async (data) => {
return request({ return request({
url: '/admin/articleCategory/add', url: '/admin/articleCategory/add',
@@ -433,7 +441,7 @@ const admin = {
data: data data: data
}); });
}, },
delArticle: async (id) => { delArticleCategory: async (id) => {
return request({ return request({
url: '/admin/articleCategory/del', url: '/admin/articleCategory/del',
method: Method.POST, method: Method.POST,
@@ -447,6 +455,96 @@ const admin = {
data: data data: data
}); });
}, },
getArticleList: async (data) => {
return request({
url: '/admin/article/getList',
method: Method.POST,
data: data
});
},
addArticle: async (data) => {
return request({
url: '/admin/article/add',
method: Method.POST,
data: data
});
},
statusArticle: async (id) => {
return request({
url: '/admin/article/status',
method: Method.POST,
data: {id}
});
},
topArticle: async (id) => {
return request({
url: '/admin/article/top',
method: Method.POST,
data: {id}
});
},
weighArticle: async (data) => {
return request({
url: '/admin/article/weigh',
method: Method.POST,
data: data
});
},
delArticle: async (id) => {
return request({
url: '/admin/article/del',
method: Method.POST,
data: {id}
});
},
editArticle: async (data) => {
return request({
url: '/admin/article/edit',
method: Method.POST,
data: data
});
},
typeArticle: async () => {
return request({
url: '/admin/article/getType',
method: Method.POST,
});
},
getSingleList: async (data) => {
return request({
url: '/admin/single/getList',
method: Method.POST,
data: data,
});
},
addSingle: async (data) => {
return request({
url: '/admin/single/add',
method: Method.POST,
data: data,
});
},
editSingle: async (data) => {
return request({
url: '/admin/single/edit',
method: Method.POST,
data: data,
});
},
delSingle: async (id) => {
return request({
url: '/admin/single/del',
method: Method.POST,
data: {id},
});
},
detailSingle: async (id) => {
return request({
url: '/admin/single/detail',
method: Method.POST,
data: {id},
});
},
} }
export default admin; export default admin;

View File

@@ -1,7 +1,8 @@
<script setup> <script setup>
import {ref, watch, computed, nextTick} from "vue"; import {computed, nextTick, ref, watch} from "vue";
import Editor from "@tinymce/tinymce-vue"; import Editor from "@tinymce/tinymce-vue";
import {VITE_TINYMCE_KEY} from "../../utils/index.js"; import {VITE_TINYMCE_KEY} from "../../utils/index.js";
import Api from "../../api/index.js";
const content = defineModel('content'); const content = defineModel('content');
const EditorIF = ref(true); const EditorIF = ref(true);
@@ -28,7 +29,13 @@ const INIT = computed(() => ({
images_upload_url: 'http://your-api/upload', images_upload_url: 'http://your-api/upload',
images_upload_credentials: true, images_upload_credentials: true,
images_upload_handler: (blobInfo, success, failure) => { images_upload_handler: (blobInfo, success, failure) => {
console.log(blobInfo, success, failure); return new Promise((resolve, reject) => {
Api.system.uploadFile(blobInfo.blob()).then(({data}) => {
resolve(data);
}).catch(err => {
reject(err);
});
})
}, },
file_picker_types: 'image', file_picker_types: 'image',
images_reuse_filename: true, images_reuse_filename: true,

View File

@@ -1,17 +1,47 @@
<script setup> <script setup>
import TinyMCE from "./index.vue"; import {ref, watch} from "vue";
import {ref} from "vue"; import TinyMCE from './index.vue';
const {title, preview} = defineProps({
title: {
type: String,
default: ''
},
preview: {
type: Boolean,
default: false,
}
});
const emits = defineEmits(['success', 'show']);
const content = defineModel('content'); const content = defineModel('content');
const contentTitle = defineModel('contentTitle');
const inputRef = ref();
const visible = ref(false); const visible = ref(false);
const fullscreen = ref(false); const fullscreen = ref(false);
watch(
() => visible.value,
(val) => {
if (val) emits('show');
}
)
const success = async () => {
emits('success');
}
const clickInput = () => {
inputRef.value.focus();
}
</script> </script>
<template> <template>
<a-link v-if="!$slots.default" :hoverable="false" @click="visible=true">编辑</a-link> <a-link v-if="!$slots.default" :hoverable="false" @click="visible=true">编辑</a-link>
<div v-else><slot></slot></div> <div v-else @click="visible=true">
<slot></slot>
</div>
<a-modal <a-modal
@ok="success"
id="TinyMCEModal" id="TinyMCEModal"
:mask-closable="false" :mask-closable="false"
:unmount-on-close="true" :unmount-on-close="true"
@@ -19,12 +49,17 @@ const fullscreen = ref(false);
width="800px" width="800px"
:draggable="true" :draggable="true"
title-align="start" title-align="start"
title="编辑" v-bind="$attrs"
v-model:visible="visible"> v-model:visible="visible">
<template #title> <template #title>
<div class="flex justify-between w-full pr-[30px]"> <div class="flex justify-between w-full pr-[30px]">
<div> <div>
编辑 {{ title }}
</div>
<div>
<a-input v-if="!preview" ref="inputRef" @click="clickInput"
v-model:model-value="contentTitle"></a-input>
<div v-else>{{ contentTitle }}</div>
</div> </div>
<a-link @click="fullscreen = !fullscreen"> <a-link @click="fullscreen = !fullscreen">
<icon-fullscreen v-if="!fullscreen"/> <icon-fullscreen v-if="!fullscreen"/>
@@ -33,9 +68,11 @@ const fullscreen = ref(false);
</div> </div>
</template> </template>
<TinyMCE <TinyMCE
v-if="!preview"
v-model:content="content" v-model:content="content"
:skin="fullscreen ? 'fluent' : 'borderless'"> :skin="fullscreen ? 'fluent' : 'borderless'">
</TinyMCE> </TinyMCE>
<div v-else v-html="content" class="p-[24px]"></div>
</a-modal> </a-modal>
</template> </template>

View File

@@ -1,12 +1,17 @@
<script setup> <script setup>
import {onMounted, reactive} from "vue"; import {onMounted, reactive} from "vue";
const {api, fieldName} = defineProps({ const {api, fieldName, apiPo} = defineProps({
api: { api: {
type: Function, type: Function,
default: async () => {}, default: async () => {
},
required: true, required: true,
}, },
apiPo: {
type: Object,
default: {}
},
fieldName: { fieldName: {
type: Object, type: Object,
default: {value: 'id', label: 'name'}, default: {value: 'id', label: 'name'},
@@ -15,7 +20,7 @@ const {api, fieldName} = defineProps({
const list = reactive([]); const list = reactive([]);
onMounted(() => { onMounted(() => {
api && api().then(({data}) => { api && api(apiPo).then(({data}) => {
list.length = 0; list.length = 0;
list.push(...data); list.push(...data);
}); });

View File

@@ -24,7 +24,7 @@ const beforeUpload = (file) => {
<a-upload draggable @before-upload="beforeUpload"> <a-upload draggable @before-upload="beforeUpload">
<template #upload-button v-if="files"> <template #upload-button v-if="files">
<div class="x-upload-one-image"> <div class="x-upload-one-image">
<a-image :preview="false" :src="files"></a-image> <a-image fit="contain" width="100%" height="100%" :preview="false" :src="files"></a-image>
</div> </div>
</template> </template>
</a-upload> </a-upload>

View File

@@ -0,0 +1,58 @@
<script setup>
import {reactive} from "vue";
import TinyMCEModal from "../../../../../components/TinyMCE/modal.vue";
import Api from "../../../../../api/index.js";
import {Message} from "@arco-design/web-vue";
const emits = defineEmits(['success']);
const {detail, preview} = defineProps({
detail: {
type: Object,
default: {}
},
preview: {
type: Boolean,
default: false,
}
});
const form = reactive({
title: null,
content: null,
});
const showModal = async () => {
if (detail.id) {
const {data: {content}} = await Api.admin.detailSingle(detail.id);
detail.content = content;
}
Object.assign(form, detail);
}
const success = async () => {
if (detail.id) {
const {msg} = await Api.admin.editSingle(form);
Message.success(msg);
} else {
const {msg} = await Api.admin.addSingle(form);
Message.success(msg);
}
emits('success');
}
</script>
<template>
<TinyMCEModal
v-model:content-title="form.title"
:preview="preview"
:title="detail?.id ? '编辑' : '新增'"
v-model:content="form.content"
v-bind="$attrs"
@show="showModal"
@success="success">
<slot></slot>
</TinyMCEModal>
</template>
<style scoped lang="scss">
</style>

View File

@@ -65,7 +65,9 @@ const success = async () => {
v-model:visible="visible"> v-model:visible="visible">
<a-form layout="vertical"> <a-form layout="vertical">
<a-form-item label="封面"> <a-form-item label="封面">
<div class="w-full h-[140px]">
<upload-one v-model:file="form.file"></upload-one> <upload-one v-model:file="form.file"></upload-one>
</div>
</a-form-item> </a-form-item>
<JumpMethod v-model:form="form" :api="Api.admin.getADVType"></JumpMethod> <JumpMethod v-model:form="form" :api="Api.admin.getADVType"></JumpMethod>
</a-form> </a-form>

View File

@@ -5,16 +5,17 @@ import useTableQuery from "../../../../../hooks/useTableQuery.js";
import Api from "../../../../../api/index.js"; import Api from "../../../../../api/index.js";
import EditBanner from "./EditBanner.vue"; import EditBanner from "./EditBanner.vue";
import XSwitch from "../../../../../components/XSwitch/index.vue"; import XSwitch from "../../../../../components/XSwitch/index.vue";
import {Message} from "@arco-design/web-vue";
const columns = [ const columns = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'key', dataIndex: 'id',
width: 120, width: 120,
}, },
{ {
title: '封面', title: '封面',
dataIndex: 'key', dataIndex: 'file',
slotName: 'file', slotName: 'file',
}, },
{ {
@@ -58,6 +59,14 @@ const {loading, pagination, fetchData} = useTableQuery({
Object.assign(vo, data); Object.assign(vo, data);
} }
}); });
const del = async (id) => {
const {code, msg} = await Api.admin.barrageDel({
id: id
});
if (code === 1) Message.success(msg);
await fetchData();
}
</script> </script>
<template> <template>
@@ -93,7 +102,7 @@ const {loading, pagination, fetchData} = useTableQuery({
<EditBanner :position="2" :detail="record" @success="fetchData"> <EditBanner :position="2" :detail="record" @success="fetchData">
<a-link :hoverable="false">编辑</a-link> <a-link :hoverable="false">编辑</a-link>
</EditBanner> </EditBanner>
<a-popconfirm content="确认删除吗?" @ok="delADV(record.id)"> <a-popconfirm content="确认删除吗?" @ok="del(record.id)">
<a-link :hoverable="false" status="danger">删除</a-link> <a-link :hoverable="false" status="danger">删除</a-link>
</a-popconfirm> </a-popconfirm>
</div> </div>

View File

@@ -1,18 +1,19 @@
<script setup> <script setup>
import TinyMCEModal from "../../../../../components/TinyMCE/modal.vue";
import {reactive} from "vue"; import {reactive} from "vue";
import useTableQuery from "../../../../../hooks/useTableQuery.js"; import useTableQuery from "../../../../../hooks/useTableQuery.js";
import Api from "../../../../../api/index.js"; import Api from "../../../../../api/index.js";
import AddRichTextContent from "./AddRichTextContent.vue";
import {Message} from "@arco-design/web-vue";
const columns = [ const columns = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'key', dataIndex: 'id',
width: 120, width: 120,
}, },
{ {
title: '标题', title: '标题',
dataIndex: 'key', dataIndex: 'title',
}, },
{ {
title: '预览', title: '预览',
@@ -35,22 +36,30 @@ const vo = reactive({
total: 0, total: 0,
}); });
const {loading, pagination, initFetchData} = useTableQuery({ const {loading, pagination, fetchData} = useTableQuery({
parameter: po, parameter: po,
api: Api.system.getData, api: Api.admin.getSingleList,
callback: (data) => { callback: (data) => {
Object.assign(vo, data); Object.assign(vo, data);
} }
}); });
const del = async (id) => {
const {msg} = await Api.admin.delSingle(id);
Message.success(msg);
await fetchData();
}
</script> </script>
<template> <template>
<AddRichTextContent @success="fetchData">
<a-button type="primary"> <a-button type="primary">
<template #icon> <template #icon>
<icon-plus/> <icon-plus/>
</template> </template>
新建 新建
</a-button> </a-button>
</AddRichTextContent>
<a-table <a-table
:loading="loading" :loading="loading"
@@ -59,13 +68,22 @@ const {loading, pagination, initFetchData} = useTableQuery({
:data="vo.rows" :data="vo.rows"
:columns="columns" :columns="columns"
class="flex-grow mt-[20px] w-full"> class="flex-grow mt-[20px] w-full">
<template v-slot:preview> <template v-slot:preview="{record}">
<a-link :hoverable="false"><icon-eye />预览</a-link> <AddRichTextContent @success="fetchData" :detail="record" :preview="true">
<a-link :hoverable="false">
<icon-eye/>
预览
</a-link>
</AddRichTextContent>
</template> </template>
<template v-slot:action="{record}"> <template v-slot:action="{record}">
<div class="flex gap-[20px]"> <div class="flex gap-[20px]">
<TinyMCEModal v-model:content="record.content"></TinyMCEModal> <AddRichTextContent @success="fetchData" :detail="record">
<a-link :hoverable="false">编辑</a-link>
</AddRichTextContent>
<a-popconfirm content="确定删除吗?" @ok="del(record.id)">
<a-link :hoverable="false" status="danger">删除</a-link> <a-link :hoverable="false" status="danger">删除</a-link>
</a-popconfirm>
</div> </div>
</template> </template>
</a-table> </a-table>

View File

@@ -1,28 +1,30 @@
<script setup> <script setup>
import SequenceAdjustment from "../../../../../../components/SequenceAdjustment/index.vue";
import EditBanner from "../EditBanner.vue"; import EditBanner from "../EditBanner.vue";
import {reactive} from "vue"; import {reactive} from "vue";
import useTableQuery from "../../../../../../hooks/useTableQuery.js"; import useTableQuery from "../../../../../../hooks/useTableQuery.js";
import Api from "../../../../../../api/index.js"; import Api from "../../../../../../api/index.js";
import {Message} from "@arco-design/web-vue";
import XSwitch from "../../../../../../components/XSwitch/index.vue";
const columns = [ const columns = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'key', dataIndex: 'id',
width: 120, width: 120,
}, },
{ {
title: '封面', title: '封面',
dataIndex: 'key', dataIndex: 'file',
slotName: 'file',
}, },
{ {
title: '跳转方式', title: '跳转方式',
dataIndex: 'key', dataIndex: 'type_text',
}, },
{ {
title: '是否启用', title: '是否启用',
dataIndex: 'isA', dataIndex: 'isStatus',
slotName: 'isA', slotName: 'isStatus',
width: 100, width: 100,
align: 'center', align: 'center',
}, },
@@ -40,29 +42,34 @@ const columns = [
}, },
]; ];
const po = reactive({}); const po = reactive({
position: 3,
});
const vo = reactive({ const vo = reactive({
page: '', page: '',
rows: [], rows: [],
total: 0, total: 0,
}); });
const {loading, pagination, initFetchData} = useTableQuery({ const {loading, pagination, fetchData} = useTableQuery({
parameter: po, parameter: po,
api: Api.system.getData, api: Api.admin.getADVList,
callback: (data) => { callback: (data) => {
Object.assign(vo, data); Object.assign(vo, data);
} }
}); });
const del = async (id) => {
const {code, msg} = await Api.admin.barrageDel({
id: id
});
if (code === 1) Message.success(msg);
await fetchData();
}
</script> </script>
<template> <template>
<a-button type="primary"> <EditBanner :position="3" @success="fetchData"></EditBanner>
<template #icon>
<icon-plus/>
</template>
新建
</a-button>
<a-table <a-table
:loading="loading" :loading="loading"
@@ -71,18 +78,25 @@ const {loading, pagination, initFetchData} = useTableQuery({
:data="vo.rows" :data="vo.rows"
:columns="columns" :columns="columns"
class="flex-grow mt-[20px] w-full"> class="flex-grow mt-[20px] w-full">
<template v-slot:isA> <template v-slot:file="{record}">
<a-switch></a-switch> <a-image height="60" :src="record.file"></a-image>
</template> </template>
<template v-slot:sort> <template v-slot:isStatus="{record}">
<SequenceAdjustment></SequenceAdjustment> <x-switch
v-model:model-value="record.status"
:id="record.id"
:api="Api.admin.setADVStatus"
@change="fetchData">
</x-switch>
</template> </template>
<template v-slot:action> <template v-slot:action="{record}">
<div class="flex gap-[10px]"> <div class="flex gap-[10px]">
<EditBanner> <EditBanner :position="3" :detail="record" @success="fetchData">
<a-link :hoverable="false">编辑</a-link> <a-link :hoverable="false">编辑</a-link>
</EditBanner> </EditBanner>
<a-popconfirm content="确认删除吗?" @ok="del(record.id)">
<a-link :hoverable="false" status="danger">删除</a-link> <a-link :hoverable="false" status="danger">删除</a-link>
</a-popconfirm>
</div> </div>
</template> </template>
</a-table> </a-table>

View File

@@ -3,38 +3,32 @@ import SequenceAdjustment from "../../../../../../components/SequenceAdjustment/
import {reactive} from "vue"; import {reactive} from "vue";
import useTableQuery from "../../../../../../hooks/useTableQuery.js"; import useTableQuery from "../../../../../../hooks/useTableQuery.js";
import Api from "../../../../../../api/index.js"; import Api from "../../../../../../api/index.js";
import XSwitch from "../../../../../../components/XSwitch/index.vue";
import {Message} from "@arco-design/web-vue";
import AddBasicTeaching from "./components/AddBasicTeaching.vue"; import AddBasicTeaching from "./components/AddBasicTeaching.vue";
const columns = [ const columns = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'key', dataIndex: 'id',
width: 120, width: 120,
}, },
{ {
title: '二级分类', title: '二级分类',
dataIndex: 'key', dataIndex: 'name',
},
{
title: '封面',
dataIndex: 'key',
}, },
{ {
title: '标题', title: '标题',
dataIndex: 'key', dataIndex: 'title',
}, },
{ {
title: '简介', title: '简介',
dataIndex: 'key', dataIndex: 'content',
},
{
title: '跳转方式',
dataIndex: 'key',
}, },
{ {
title: '是否启用', title: '是否启用',
dataIndex: 'isA', dataIndex: 'isStatus',
slotName: 'isA', slotName: 'isStatus',
width: 100, width: 100,
align: 'center', align: 'center',
}, },
@@ -58,24 +52,35 @@ const columns = [
width: 120, width: 120,
}, },
]; ];
const po = reactive({}); const po = reactive({
pid: 2
});
const vo = reactive({ const vo = reactive({
page: '', page: '',
rows: [], rows: [],
total: 0, total: 0,
}); });
const {loading, pagination, initFetchData} = useTableQuery({ const {loading, pagination, fetchData} = useTableQuery({
parameter: po, parameter: po,
api: Api.system.getData, api: Api.admin.getArticleList,
callback: (data) => { callback: (data) => {
Object.assign(vo, data); Object.assign(vo, data);
} }
}); });
const del = async (id) => {
const {msg} = await Api.admin.delArticle(id);
Message.success(msg);
await fetchData();
}
</script> </script>
<template> <template>
<AddBasicTeaching></AddBasicTeaching> <AddBasicTeaching
:pid="2"
@success="fetchData">
</AddBasicTeaching>
<a-table <a-table
:loading="loading" :loading="loading"
@@ -84,21 +89,40 @@ const {loading, pagination, initFetchData} = useTableQuery({
:data="vo.rows" :data="vo.rows"
:columns="columns" :columns="columns"
class="flex-grow mt-[20px] w-full"> class="flex-grow mt-[20px] w-full">
<template v-slot:isA> <template v-slot:isStatus="{record}">
<a-switch></a-switch> <x-switch
v-model:model-value="record.status"
:id="record.id"
:api="Api.admin.statusArticle"
@change="fetchData">
</x-switch>
</template> </template>
<template v-slot:isTop> <template v-slot:isTop="{record}">
<a-switch></a-switch> <x-switch
v-model:model-value="record.is_top"
:id="record.id"
:api="Api.admin.topArticle"
@change="fetchData">
</x-switch>
</template> </template>
<template v-slot:sort> <template v-slot:sort="{record}">
<SequenceAdjustment></SequenceAdjustment> <SequenceAdjustment
:id="record.id"
@success="fetchData"
:api="Api.admin.weighArticle">
</SequenceAdjustment>
</template> </template>
<template v-slot:action> <template v-slot:action="{record}">
<div class="flex gap-[20px]"> <div class="flex gap-[20px]">
<AddBasicTeaching> <AddBasicTeaching
@success="fetchData"
:detail="record"
:pid="2">
<a-link :hoverable="false">编辑</a-link> <a-link :hoverable="false">编辑</a-link>
</AddBasicTeaching> </AddBasicTeaching>
<a-popconfirm content="确认删除吗?" @ok="del(record.id)">
<a-link :hoverable="false" status="danger">删除</a-link> <a-link :hoverable="false" status="danger">删除</a-link>
</a-popconfirm>
</div> </div>
</template> </template>
</a-table> </a-table>

View File

@@ -4,29 +4,31 @@ import {reactive} from "vue";
import useTableQuery from "../../../../../../hooks/useTableQuery.js"; import useTableQuery from "../../../../../../hooks/useTableQuery.js";
import Api from "../../../../../../api/index.js"; import Api from "../../../../../../api/index.js";
import AddFrequentlyQuestions from "./components/AddFrequentlyQuestions.vue"; import AddFrequentlyQuestions from "./components/AddFrequentlyQuestions.vue";
import XSwitch from "../../../../../../components/XSwitch/index.vue";
import {Message} from "@arco-design/web-vue";
const columns = [ const columns = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'key', dataIndex: 'id',
width: 120, width: 120,
}, },
{ {
title: '二级分类', title: '二级分类',
dataIndex: 'key', dataIndex: 'name',
}, },
{ {
title: '标题', title: '标题',
dataIndex: 'key', dataIndex: 'title',
}, },
{ {
title: '简介', title: '简介',
dataIndex: 'key', dataIndex: 'content',
}, },
{ {
title: '是否启用', title: '是否启用',
dataIndex: 'isA', dataIndex: 'isStatus',
slotName: 'isA', slotName: 'isStatus',
width: 100, width: 100,
align: 'center', align: 'center',
}, },
@@ -50,7 +52,9 @@ const columns = [
width: 120, width: 120,
}, },
]; ];
const po = reactive({}); const po = reactive({
pid: 1
});
const vo = reactive({ const vo = reactive({
page: '', page: '',
rows: [], rows: [],
@@ -59,15 +63,22 @@ const vo = reactive({
const {loading, pagination, fetchData} = useTableQuery({ const {loading, pagination, fetchData} = useTableQuery({
parameter: po, parameter: po,
api: Api.admin.getArticlevategoryList, api: Api.admin.getArticleList,
callback: (data) => { callback: (data) => {
Object.assign(vo, data); Object.assign(vo, data);
} }
}); });
const del = async (id) => {
const {msg} = await Api.admin.delArticle(id);
Message.success(msg);
await fetchData();
}
</script> </script>
<template> <template>
<AddFrequentlyQuestions <AddFrequentlyQuestions
:pid="1"
@success="fetchData"> @success="fetchData">
</AddFrequentlyQuestions> </AddFrequentlyQuestions>
@@ -78,21 +89,40 @@ const {loading, pagination, fetchData} = useTableQuery({
:data="vo.rows" :data="vo.rows"
:columns="columns" :columns="columns"
class="flex-grow mt-[20px] w-full"> class="flex-grow mt-[20px] w-full">
<template v-slot:isA> <template v-slot:isStatus="{record}">
<a-switch></a-switch> <x-switch
v-model:model-value="record.status"
:id="record.id"
:api="Api.admin.statusArticle"
@change="fetchData">
</x-switch>
</template> </template>
<template v-slot:isTop> <template v-slot:isTop="{record}">
<a-switch></a-switch> <x-switch
v-model:model-value="record.is_top"
:id="record.id"
:api="Api.admin.topArticle"
@change="fetchData">
</x-switch>
</template> </template>
<template v-slot:sort> <template v-slot:sort="{record}">
<SequenceAdjustment></SequenceAdjustment> <SequenceAdjustment
:id="record.id"
@success="fetchData"
:api="Api.admin.weighArticle">
</SequenceAdjustment>
</template> </template>
<template v-slot:action> <template v-slot:action="{record}">
<div class="flex gap-[20px]"> <div class="flex gap-[20px]">
<AddFrequentlyQuestions> <AddFrequentlyQuestions
@success="fetchData"
:detail="record"
:pid="1">
<a-link :hoverable="false">编辑</a-link> <a-link :hoverable="false">编辑</a-link>
</AddFrequentlyQuestions> </AddFrequentlyQuestions>
<a-popconfirm content="确认删除吗?" @ok="del(record.id)">
<a-link :hoverable="false" status="danger">删除</a-link> <a-link :hoverable="false" status="danger">删除</a-link>
</a-popconfirm>
</div> </div>
</template> </template>
</a-table> </a-table>

View File

@@ -59,7 +59,7 @@ const {loading: loading2, pagination: pagination2, fetchData: fetchData2} = useT
}); });
const del = async (id) => { const del = async (id) => {
const {msg} = await Api.admin.delArticle(id); const {msg} = await Api.admin.delArticleCategory(id);
Message.success(msg); Message.success(msg);
await fetchData1(); await fetchData1();
await fetchData2(); await fetchData2();

View File

@@ -1,14 +1,47 @@
<script setup> <script setup>
import Api from "../../../../../../../api/index.js"; import JumpMethod from "../../../../../../../components/JumpMethod/index.vue";
import {reactive, ref, watch} from 'vue';
import XSelect from "../../../../../../../components/XSelect/index.vue"; import XSelect from "../../../../../../../components/XSelect/index.vue";
import JumpMethod from '../../../../../../../components/JumpMethod/index.vue'; import Api from "../../../../../../../api/index.js";
import {reactive, ref} from "vue"; import {Message} from "@arco-design/web-vue";
const emits = defineEmits(['success']);
const {pid, detail} = defineProps({
pid: {
type: Number,
default: 2,
},
detail: {
type: Object,
default: {}
}
});
const visible = ref(false); const visible = ref(false);
const form = reactive({ const form = reactive({
type: null,
title: null, title: null,
category_id: null,
content: null,
}); });
watch(
() => visible.value,
(val) => {
if (val) Object.assign(form, detail);
}
)
const success = async () => {
if (detail.id) {
const {msg} = await Api.admin.editArticle({...form, pid});
Message.success(msg);
} else {
const {msg} = await Api.admin.addArticle({...form, pid});
Message.success(msg);
}
emits('success');
}
</script> </script>
<template> <template>
@@ -24,6 +57,7 @@ const form = reactive({
<a-modal <a-modal
@ok="success"
title="新增常见问题" title="新增常见问题"
title-align="start" title-align="start"
v-model:visible="visible"> v-model:visible="visible">
@@ -31,20 +65,20 @@ const form = reactive({
layout="vertical" layout="vertical"
:model="form"> :model="form">
<a-form-item label="二级分类"> <a-form-item label="二级分类">
<XSelect :api="Api.system.getSelect" placeholder="请选择二级分类"></XSelect> <XSelect
</a-form-item> v-model:model-value="form.category_id"
<a-form-item label="标题"> :api="Api.admin.getArticleCategoryList2"
<a-upload></a-upload> :api-po="{pid}"
placeholder="请选择二级分类">
</XSelect>
</a-form-item> </a-form-item>
<a-form-item label="标题"> <a-form-item label="标题">
<a-input v-model:model-value="form.title" placeholder="请输入标题"></a-input> <a-input v-model:model-value="form.title" placeholder="请输入标题"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="简介"> <a-form-item label="简介">
<a-textarea placeholder="请输入简介"></a-textarea> <a-textarea v-model:model-value="form.content" placeholder="请输入简介"></a-textarea>
</a-form-item>
<a-form-item label="跳转方式">
<JumpMethod></JumpMethod>
</a-form-item> </a-form-item>
<JumpMethod v-model:form="form" :api="Api.admin.typeArticle"></JumpMethod>
</a-form> </a-form>
</a-modal> </a-modal>
</template> </template>

View File

@@ -1,13 +1,45 @@
<script setup> <script setup>
import {ref, reactive} from 'vue'; import {reactive, ref, watch} from 'vue';
import XSelect from "../../../../../../../components/XSelect/index.vue"; import XSelect from "../../../../../../../components/XSelect/index.vue";
import Api from "../../../../../../../api/index.js"; import Api from "../../../../../../../api/index.js";
import {Message} from "@arco-design/web-vue";
const emits = defineEmits(['success']);
const {pid, detail} = defineProps({
pid: {
type: Number,
default: 1,
},
detail: {
type: Object,
default: {}
}
});
const visible = ref(false); const visible = ref(false);
const form = reactive({ const form = reactive({
title: null, title: null,
category_id: null,
content: null,
}); });
watch(
() => visible.value,
(val) => {
if (val) Object.assign(form, detail);
}
)
const success = async () => {
if (detail.id) {
const {msg} = await Api.admin.editArticle({...form, pid});
Message.success(msg);
} else {
const {msg} = await Api.admin.addArticle({...form, pid});
Message.success(msg);
}
emits('success');
}
</script> </script>
<template> <template>
@@ -23,6 +55,7 @@ const form = reactive({
<a-modal <a-modal
@ok="success"
title="新增常见问题" title="新增常见问题"
title-align="start" title-align="start"
v-model:visible="visible"> v-model:visible="visible">
@@ -30,13 +63,18 @@ const form = reactive({
layout="vertical" layout="vertical"
:model="form"> :model="form">
<a-form-item label="二级分类"> <a-form-item label="二级分类">
<XSelect :api="Api.system.getSelect" placeholder="请选择二级分类"></XSelect> <XSelect
v-model:model-value="form.category_id"
:api="Api.admin.getArticleCategoryList2"
:api-po="{pid}"
placeholder="请选择二级分类">
</XSelect>
</a-form-item> </a-form-item>
<a-form-item label="标题"> <a-form-item label="标题">
<a-input v-model:model-value="form.title" placeholder="请输入标题"></a-input> <a-input v-model:model-value="form.title" placeholder="请输入标题"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="简介"> <a-form-item label="简介">
<a-textarea placeholder="请输入简介"></a-textarea> <a-textarea v-model:model-value="form.content" placeholder="请输入简介"></a-textarea>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>