|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
|
|
|
|
-<div>
|
|
|
+ <div style="padding-bottom: 200px;">
|
|
|
<a-breadcrumb>
|
|
|
<a-breadcrumb-item>WebChat</a-breadcrumb-item>
|
|
|
<a-breadcrumb-item>控制台</a-breadcrumb-item>
|
|
@@ -10,46 +10,193 @@
|
|
|
|
|
|
<div class="edit-container">
|
|
|
<Toolbar
|
|
|
- style="border: none; margin-top: 20px; background-color: whitesmoke;"
|
|
|
+ style="border: none; margin-top: 20px; background-color: whitesmoke; margin-bottom: 20px;"
|
|
|
:editor="editorRef"
|
|
|
:defaultConfig="toolbarConfig"
|
|
|
:mode="mode"
|
|
|
/>
|
|
|
- <div class="edit-body-container">
|
|
|
+ <div class="edit-body-container" style="min-height: 400px; height: auto;">
|
|
|
<input class="edit-title" :value="title" placeholder="文章标题">
|
|
|
- <Editor
|
|
|
- style="height: auto; min-height: 500px; width: 100%;"
|
|
|
+ <Editor id="edit-content"
|
|
|
v-model="valueHtml"
|
|
|
:defaultConfig="editorConfig"
|
|
|
:mode="mode"
|
|
|
@onCreated="handleCreated"
|
|
|
/>
|
|
|
</div>
|
|
|
-
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div class="edit-plugin-container-title">
|
|
|
+ 封面和摘要
|
|
|
+ </div>
|
|
|
+ <div style="display: flex;">
|
|
|
+ <a-upload
|
|
|
+ class="article-cover"
|
|
|
+ name="articleCover"
|
|
|
+ :action="uploadUrl"
|
|
|
+ list-type="picture-card"
|
|
|
+ :show-upload-list="false"
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ >
|
|
|
+ <div v-if="!articleCover">
|
|
|
+ <a-icon type="plus" />
|
|
|
+ <div style="margin-top: 8px">上传封面</div>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <img :src="articleCover" alt="封面图" style="width: 100%; display: block" />
|
|
|
+ </div>
|
|
|
+ </a-upload>
|
|
|
+ <a-textarea
|
|
|
+ style=" margin-left: 20px; height: 125px;"
|
|
|
+ v-model:value="value2"
|
|
|
+ placeholder="文章摘要"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div class="edit-plugin-container-title">
|
|
|
+ 绑定公众号
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <a-select
|
|
|
+ show-search
|
|
|
+ placeholder="请选择推文公众号"
|
|
|
+ style="width: 200px"
|
|
|
+ :options="officalAccountOptions"
|
|
|
+ @focus="handleFocus"
|
|
|
+ @blur="handleBlur"
|
|
|
+ @change="handleChange"
|
|
|
+ >
|
|
|
+ </a-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div class="edit-plugin-container-title">
|
|
|
+ 计划推送时间
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <a-date-picker show-time>
|
|
|
+ <template #renderExtraFooter>extra footer</template>
|
|
|
+ </a-date-picker>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div class="edit-plugin-container-title">
|
|
|
+ 外部链接(非必填)
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <a-input class="edit-input" placeholder="如果指定外部链接则优先跳转到指定链接地址" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div class="edit-plugin-container-title">
|
|
|
+ 文章标签
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <a-input class="edit-input" placeholder="多个标签请用英文逗号分割,如:标签A,标签B,标签C" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="edit-plugin-container">
|
|
|
+ <div>
|
|
|
+ <a-button type="primary" style="width: 200px; height: 45px; background-color: black;">推送文章</a-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
-<script >
|
|
|
-import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
|
|
-
|
|
|
-import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
|
|
|
-import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
|
|
+<script>
|
|
|
+import axios from 'axios';
|
|
|
+import '@wangeditor/editor/dist/css/style.css';
|
|
|
+import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue';
|
|
|
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
|
|
|
export default {
|
|
|
components: { Editor, Toolbar },
|
|
|
setup() {
|
|
|
+ const route = useRoute();
|
|
|
+ const oauthCode = ref(route.query.oauthCode || new URLSearchParams(window.location.search).get('oauthCode'));
|
|
|
// 编辑器实例,必须用 shallowRef
|
|
|
const editorRef = shallowRef()
|
|
|
-
|
|
|
// 内容 HTML
|
|
|
const valueHtml = ref('')
|
|
|
+ const officalAccountOptions = ref([])
|
|
|
+ const articleCover = ref(null);
|
|
|
+ const uploadUrl = '/admin-service/file/upload';
|
|
|
+
|
|
|
+ const handleArticleCoverUpload = async (file) => {
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('file', file);
|
|
|
+ try {
|
|
|
+ const response = await axios.post(uploadUrl, formData, {
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'multipart/form-data',
|
|
|
+ 'oauth-code': oauthCode.value,
|
|
|
+ 'origin-url': window.location.href,
|
|
|
+ 'upload-path': 'images/avatar'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (response.data.code === 40001) {
|
|
|
+ window.location.href = response.data.redirect_url;
|
|
|
+ }
|
|
|
+ // 假设服务器返回头像的 URL
|
|
|
+ articleCover.value = response.data.data.url;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error uploading avatar:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const beforeUpload = async (file) => {
|
|
|
+ // 文件验证逻辑,例如限制文件大小和类型
|
|
|
+ const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
|
|
+ const isLt2M = file.size / 1024 / 1024 < 2;
|
|
|
+
|
|
|
+ if (!isJpgOrPng) {
|
|
|
+ message.error('请上传 JPG 或 PNG 格式的图片');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!isLt2M) {
|
|
|
+ message.error('图片大小不能超过 2MB');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ await handleArticleCoverUpload(file);
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+
|
|
|
+ const listOficalAccounts = async () => {
|
|
|
+ try {
|
|
|
+ const response = await axios.get(`/admin-service/account/page`, {
|
|
|
+ params: {
|
|
|
+ roleCode: 6,
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: 20
|
|
|
+ },
|
|
|
+ headers: {
|
|
|
+ 'oauth-code': oauthCode.value,
|
|
|
+ 'origin-url': window.location.href
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (response.data.code === 40001) {
|
|
|
+ // 未登录
|
|
|
+ window.location.href = response.data.redirect_url;
|
|
|
+ }
|
|
|
+ // 使用 map 方法进行转换
|
|
|
+ officalAccountOptions.value = response.data.data.map(item => ({
|
|
|
+ value: item.userId,
|
|
|
+ label: item.userName
|
|
|
+ }));
|
|
|
+ } catch (error) {
|
|
|
+ message.error('公众号列表加载失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ listOficalAccounts();
|
|
|
|
|
|
// 模拟 ajax 异步获取内容
|
|
|
onMounted(() => {
|
|
|
|
|
|
-
|
|
|
+
|
|
|
})
|
|
|
|
|
|
const toolbarConfig = {}
|
|
@@ -67,12 +214,18 @@ export default {
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
+ articleCover,
|
|
|
+ uploadUrl,
|
|
|
editorRef,
|
|
|
valueHtml,
|
|
|
+ officalAccountOptions,
|
|
|
mode: 'default', // 或 'simple'
|
|
|
toolbarConfig,
|
|
|
editorConfig,
|
|
|
handleCreated,
|
|
|
+ listOficalAccounts,
|
|
|
+ handleArticleCoverUpload,
|
|
|
+ beforeUpload
|
|
|
}
|
|
|
},
|
|
|
}
|
|
@@ -86,7 +239,8 @@ export default {
|
|
|
align-items: center;
|
|
|
}
|
|
|
.edit-body-container {
|
|
|
- width: 80%;
|
|
|
+ width: 70%;
|
|
|
+ min-width: 600px;
|
|
|
}
|
|
|
.edit-title {
|
|
|
width: 100%;
|
|
@@ -100,4 +254,42 @@ export default {
|
|
|
outline: 0px;
|
|
|
background-color: white;
|
|
|
}
|
|
|
+ .edit-plugin-container {
|
|
|
+ position: relative;
|
|
|
+ width: 70%;
|
|
|
+ margin-top: 30px;
|
|
|
+ }
|
|
|
+ .edit-plugin-container-title {
|
|
|
+ text-align: left;
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ color: #353535;
|
|
|
+ }
|
|
|
+ .edit-input {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 45px;
|
|
|
+ line-height: 45px;
|
|
|
+ border-radius: 3px;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ }
|
|
|
+ .article-cover.ant-upload-wrapper.ant-upload-picture-card-wrapper {
|
|
|
+ width: 250px;
|
|
|
+ height: 125px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .article-cover.ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload.ant-upload-select {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ margin-inline-end: 8px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ text-align: center;
|
|
|
+ vertical-align: top;
|
|
|
+ background-color: rgba(0, 0, 0, 0.02);
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: border-color 0.3s;
|
|
|
+}
|
|
|
</style>
|