Pre Merge pull request !102 from dhb52/master
						commit
						b5a09027ad
					
				|  | @ -27,10 +27,12 @@ | ||||||
|     "lint:pretty": "pretty-quick --staged" |     "lint:pretty": "pretty-quick --staged" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "@element-plus/icons-vue": "^2.1.0", | ||||||
|     "@form-create/designer": "^3.1.0", |     "@form-create/designer": "^3.1.0", | ||||||
|     "@form-create/element-ui": "^3.1.17", |     "@form-create/element-ui": "^3.1.17", | ||||||
|     "@iconify/iconify": "^3.1.0", |     "@iconify/iconify": "^3.1.0", | ||||||
|     "@videojs-player/vue": "^1.0.0", |     "@videojs-player/vue": "^1.0.0", | ||||||
|  |     "@vueup/vue-quill": "^1.1.1", | ||||||
|     "@vueuse/core": "^9.13.0", |     "@vueuse/core": "^9.13.0", | ||||||
|     "@wangeditor/editor": "^5.1.23", |     "@wangeditor/editor": "^5.1.23", | ||||||
|     "@wangeditor/editor-for-vue": "^5.1.10", |     "@wangeditor/editor-for-vue": "^5.1.10", | ||||||
|  |  | ||||||
|  | @ -0,0 +1,201 @@ | ||||||
|  | <script setup> | ||||||
|  | import { ref, reactive } from 'vue' | ||||||
|  | import { QuillEditor } from '@vueup/vue-quill' | ||||||
|  | import '@vueup/vue-quill/dist/vue-quill.snow.css' | ||||||
|  | import { getAccessToken } from '@/utils/auth' | ||||||
|  | import editorOptions from './quill-options' | ||||||
|  | 
 | ||||||
|  | const BASE_URL = import.meta.env.VITE_BASE_URL | ||||||
|  | 
 | ||||||
|  | const message = useMessage() | ||||||
|  | 
 | ||||||
|  | const props = defineProps({ | ||||||
|  |   /* 公众号账号编号 */ | ||||||
|  |   accountId: { | ||||||
|  |     type: Number, | ||||||
|  |     required: true | ||||||
|  |   }, | ||||||
|  |   /* 编辑器的内容 */ | ||||||
|  |   value: { | ||||||
|  |     type: String, | ||||||
|  |     default: '' | ||||||
|  |   }, | ||||||
|  |   /* 图片大小 */ | ||||||
|  |   maxSize: { | ||||||
|  |     type: Number, | ||||||
|  |     default: 4000 // kb | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['input']) | ||||||
|  | 
 | ||||||
|  | const myQuillEditorRef = ref() | ||||||
|  | 
 | ||||||
|  | const content = ref(props.value.replace(/data-src/g, 'src')) | ||||||
|  | 
 | ||||||
|  | const loading = ref(false) // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示 | ||||||
|  | 
 | ||||||
|  | const actionUrl = ref(BASE_URL + '/admin-api/mp/material/upload-news-image') // 这里写你要上传的图片服务器地址 | ||||||
|  | const headers = ref({ Authorization: 'Bearer ' + getAccessToken() }) // 设置上传的请求头部 | ||||||
|  | const uploadData = reactive({ | ||||||
|  |   type: 'image', // TODO 芋艿:试试要不要换成 thumb | ||||||
|  |   accountId: props.accountId | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const onEditorChange = () => { | ||||||
|  |   //内容改变事件 | ||||||
|  |   emit('input', content.value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 富文本图片上传前 | ||||||
|  | const beforeUpload = () => { | ||||||
|  |   // 显示 loading 动画 | ||||||
|  |   loading.value = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 图片上传成功 | ||||||
|  | // 注意!由于微信公众号的图片有访问限制,所以会显示“此图片来自微信公众号,未经允许不可引用” | ||||||
|  | const uploadSuccess = (res) => { | ||||||
|  |   // res为图片服务器返回的数据 | ||||||
|  |   // 获取富文本组件实例 | ||||||
|  |   const quill = myQuillEditorRef.value.quill | ||||||
|  |   // 如果上传成功 | ||||||
|  |   const link = res.data | ||||||
|  |   if (link) { | ||||||
|  |     // 获取光标所在位置 | ||||||
|  |     let length = quill.getSelection().index | ||||||
|  |     // 插入图片  res.info为服务器返回的图片地址 | ||||||
|  |     quill.insertEmbed(length, 'image', link) | ||||||
|  |     // 调整光标到最后 | ||||||
|  |     quill.setSelection(length + 1) | ||||||
|  |   } else { | ||||||
|  |     message.error('图片插入失败') | ||||||
|  |   } | ||||||
|  |   // loading 动画消失 | ||||||
|  |   loading.value = false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 富文本图片上传失败 | ||||||
|  | const uploadError = () => { | ||||||
|  |   // loading 动画消失 | ||||||
|  |   loading.value = false | ||||||
|  |   message.error('图片插入失败') | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div id="wxEditor"> | ||||||
|  |     <div v-loading="loading" element-loading-text="请稍等,图片上传中"> | ||||||
|  |       <!-- 图片上传组件辅助--> | ||||||
|  |       <el-upload | ||||||
|  |         class="avatar-uploader" | ||||||
|  |         name="file" | ||||||
|  |         :action="actionUrl" | ||||||
|  |         :headers="headers" | ||||||
|  |         :show-file-list="false" | ||||||
|  |         :data="uploadData" | ||||||
|  |         :on-success="uploadSuccess" | ||||||
|  |         :on-error="uploadError" | ||||||
|  |         :before-upload="beforeUpload" | ||||||
|  |       /> | ||||||
|  |       <QuillEditor | ||||||
|  |         class="editor" | ||||||
|  |         v-model="content" | ||||||
|  |         ref="quillEditorRef" | ||||||
|  |         :options="editorOptions" | ||||||
|  |         @change="onEditorChange($event)" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  | .editor { | ||||||
|  |   line-height: normal !important; | ||||||
|  |   height: 500px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-tooltip[data-mode='link']::before { | ||||||
|  |   content: '请输入链接地址:'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-tooltip.ql-editing a.ql-action::after { | ||||||
|  |   border-right: 0; | ||||||
|  |   content: '保存'; | ||||||
|  |   padding-right: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-tooltip[data-mode='video']::before { | ||||||
|  |   content: '请输入视频地址:'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-label::before, | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-item::before { | ||||||
|  |   content: '14px'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before, | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before { | ||||||
|  |   content: '10px'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before, | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before { | ||||||
|  |   content: '18px'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before, | ||||||
|  | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before { | ||||||
|  |   content: '32px'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item::before { | ||||||
|  |   content: '文本'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before { | ||||||
|  |   content: '标题1'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before { | ||||||
|  |   content: '标题2'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before { | ||||||
|  |   content: '标题3'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before { | ||||||
|  |   content: '标题4'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before { | ||||||
|  |   content: '标题5'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before, | ||||||
|  | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before { | ||||||
|  |   content: '标题6'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-label::before, | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-item::before { | ||||||
|  |   content: '标准字体'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before, | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before { | ||||||
|  |   content: '衬线字体'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before, | ||||||
|  | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before { | ||||||
|  |   content: '等宽字体'; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | @ -0,0 +1,45 @@ | ||||||
|  | const toolbarOptions = [ | ||||||
|  |   ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
 | ||||||
|  |   ['blockquote', 'code-block'], // 引用  代码块
 | ||||||
|  |   [{ header: 1 }, { header: 2 }], // 1、2 级标题
 | ||||||
|  |   [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
 | ||||||
|  |   [{ script: 'sub' }, { script: 'super' }], // 上标/下标
 | ||||||
|  |   [{ indent: '-1' }, { indent: '+1' }], // 缩进
 | ||||||
|  |   // [{'direction': 'rtl'}],                         // 文本方向
 | ||||||
|  |   [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
 | ||||||
|  |   [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
 | ||||||
|  |   [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
 | ||||||
|  |   [{ font: [] }], // 字体种类
 | ||||||
|  |   [{ align: [] }], // 对齐方式
 | ||||||
|  |   ['clean'], // 清除文本格式
 | ||||||
|  |   ['link', 'image', 'video'] // 链接、图片、视频
 | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | export default { | ||||||
|  |   theme: 'snow', | ||||||
|  |   placeholder: '请输入文章内容', | ||||||
|  |   modules: { | ||||||
|  |     toolbar: { | ||||||
|  |       container: toolbarOptions, | ||||||
|  |       // container: "#toolbar",
 | ||||||
|  |       handlers: { | ||||||
|  |         image: function (value) { | ||||||
|  |           if (value) { | ||||||
|  |             // 触发input框选择图片文件
 | ||||||
|  |             document.querySelector('.avatar-uploader input').click() | ||||||
|  |           } else { | ||||||
|  |             this.quill.format('image', false) | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         link: function (value) { | ||||||
|  |           if (value) { | ||||||
|  |             const href = prompt('注意!只支持公众号图文链接') | ||||||
|  |             this.quill.format('link', href) | ||||||
|  |           } else { | ||||||
|  |             this.quill.format('link', false) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -5,127 +5,130 @@ | ||||||
|   ① 移除 avue 组件,使用 ElementUI 原生组件 |   ① 移除 avue 组件,使用 ElementUI 原生组件 | ||||||
| --> | --> | ||||||
| <template> | <template> | ||||||
|   <!-- 类型:图片 --> |   <div class="pb-30px"> | ||||||
|   <div v-if="objData.type === 'image'"> |     <!-- 类型:image --> | ||||||
|     <div class="waterfall" v-loading="loading"> |     <div v-if="objData.type === 'image'"> | ||||||
|       <div class="waterfall-item" v-for="item in list" :key="item.mediaId"> |       <div class="waterfall" v-loading="loading"> | ||||||
|         <img class="material-img" :src="item.url" /> |         <div class="waterfall-item" v-for="item in list" :key="item.mediaId"> | ||||||
|         <p class="item-name">{{ item.name }}</p> |           <img class="material-img" :src="item.url" /> | ||||||
|         <el-row class="ope-row"> |           <p class="item-name">{{ item.name }}</p> | ||||||
|           <el-button type="success" @click="selectMaterialFun(item)" |  | ||||||
|             >选择 |  | ||||||
|             <i class="el-icon-circle-check el-icon--right"></i> |  | ||||||
|           </el-button> |  | ||||||
|         </el-row> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <!-- 分页组件 --> |  | ||||||
|     <pagination |  | ||||||
|       v-show="total > 0" |  | ||||||
|       :total="total" |  | ||||||
|       v-model:page="queryParams.pageNo" |  | ||||||
|       v-model:limit="queryParams.pageSize" |  | ||||||
|       @pagination="getMaterialPageFun" |  | ||||||
|     /> |  | ||||||
|   </div> |  | ||||||
|   <!-- 类型:语音 --> |  | ||||||
|   <div v-else-if="objData.type === 'voice'"> |  | ||||||
|     <!-- 列表 --> |  | ||||||
|     <el-table v-loading="loading" :data="list"> |  | ||||||
|       <el-table-column label="编号" align="center" prop="mediaId" /> |  | ||||||
|       <el-table-column label="文件名" align="center" prop="name" /> |  | ||||||
|       <el-table-column label="语音" align="center"> |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <wx-voice-player :url="scope.row.url" /> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|       <el-table-column label="上传时间" align="center" prop="createTime" width="180"> |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <span>{{ formatDate(scope.row.createTime) }}</span> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|       <el-table-column |  | ||||||
|         label="操作" |  | ||||||
|         align="center" |  | ||||||
|         fixed="right" |  | ||||||
|         class-name="small-padding fixed-width" |  | ||||||
|       > |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <el-button type="text" icon="el-icon-circle-plus" @click="selectMaterialFun(scope.row)" |  | ||||||
|             >选择 |  | ||||||
|           </el-button> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|     </el-table> |  | ||||||
|     <!-- 分页组件 --> |  | ||||||
|     <pagination |  | ||||||
|       v-show="total > 0" |  | ||||||
|       :total="total" |  | ||||||
|       v-model:page="queryParams.pageNo" |  | ||||||
|       v-model:limit="queryParams.pageSize" |  | ||||||
|       @pagination="getPage" |  | ||||||
|     /> |  | ||||||
|   </div> |  | ||||||
|   <div v-else-if="objData.type === 'video'"> |  | ||||||
|     <!-- 列表 --> |  | ||||||
|     <el-table v-loading="loading" :data="list"> |  | ||||||
|       <el-table-column label="编号" align="center" prop="mediaId" /> |  | ||||||
|       <el-table-column label="文件名" align="center" prop="name" /> |  | ||||||
|       <el-table-column label="标题" align="center" prop="title" /> |  | ||||||
|       <el-table-column label="介绍" align="center" prop="introduction" /> |  | ||||||
|       <el-table-column label="视频" align="center"> |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <wx-video-player :url="scope.row.url" /> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|       <el-table-column label="上传时间" align="center" prop="createTime" width="180"> |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <span>{{ formatDate(scope.row.createTime) }}</span> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|       <el-table-column |  | ||||||
|         label="操作" |  | ||||||
|         align="center" |  | ||||||
|         fixed="right" |  | ||||||
|         class-name="small-padding fixed-width" |  | ||||||
|       > |  | ||||||
|         <template #default="scope"> |  | ||||||
|           <el-button type="text" icon="el-icon-circle-plus" @click="selectMaterialFun(scope.row)" |  | ||||||
|             >选择 |  | ||||||
|           </el-button> |  | ||||||
|         </template> |  | ||||||
|       </el-table-column> |  | ||||||
|     </el-table> |  | ||||||
|     <!-- 分页组件 --> |  | ||||||
|     <pagination |  | ||||||
|       v-show="total > 0" |  | ||||||
|       :total="total" |  | ||||||
|       v-model:page="queryParams.pageNo" |  | ||||||
|       v-model:limit="queryParams.pageSize" |  | ||||||
|       @pagination="getMaterialPageFun" |  | ||||||
|     /> |  | ||||||
|   </div> |  | ||||||
|   <div v-else-if="objData.type === 'news'"> |  | ||||||
|     <div class="waterfall" v-loading="loading"> |  | ||||||
|       <div class="waterfall-item" v-for="item in list" :key="item.mediaId"> |  | ||||||
|         <div v-if="item.content && item.content.newsItem"> |  | ||||||
|           <wx-news :articles="item.content.newsItem" /> |  | ||||||
|           <el-row class="ope-row"> |           <el-row class="ope-row"> | ||||||
|             <el-button type="success" @click="selectMaterialFun(item)"> |             <el-button type="success" @click="selectMaterialFun(item)" | ||||||
|               选择<i class="el-icon-circle-check el-icon--right"></i> |               >选择 <Icon icon="ep:circle-check" /> | ||||||
|             </el-button> |             </el-button> | ||||||
|           </el-row> |           </el-row> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  |       <!-- 分页组件 --> | ||||||
|  |       <pagination | ||||||
|  |         v-show="total > 0" | ||||||
|  |         :total="total" | ||||||
|  |         v-model:page="queryParams.pageNo" | ||||||
|  |         v-model:limit="queryParams.pageSize" | ||||||
|  |         @pagination="getMaterialPageFun" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |     <!-- 类型:voice --> | ||||||
|  |     <div v-else-if="objData.type === 'voice'"> | ||||||
|  |       <!-- 列表 --> | ||||||
|  |       <el-table v-loading="loading" :data="list"> | ||||||
|  |         <el-table-column label="编号" align="center" prop="mediaId" /> | ||||||
|  |         <el-table-column label="文件名" align="center" prop="name" /> | ||||||
|  |         <el-table-column label="语音" align="center"> | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <WxVoicePlayer :url="scope.row.url" /> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |         <el-table-column label="上传时间" align="center" prop="createTime" width="180"> | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <span>{{ formatDate(scope.row.createTime) }}</span> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |         <el-table-column | ||||||
|  |           label="操作" | ||||||
|  |           align="center" | ||||||
|  |           fixed="right" | ||||||
|  |           class-name="small-padding fixed-width" | ||||||
|  |         > | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <el-button type="text" @click="selectMaterialFun(scope.row)" | ||||||
|  |               >选择<Icon icon="ep:plus" /> | ||||||
|  |             </el-button> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |       </el-table> | ||||||
|  |       <!-- 分页组件 --> | ||||||
|  |       <pagination | ||||||
|  |         v-show="total > 0" | ||||||
|  |         :total="total" | ||||||
|  |         v-model:page="queryParams.pageNo" | ||||||
|  |         v-model:limit="queryParams.pageSize" | ||||||
|  |         @pagination="getPage" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |     <!-- 类型:video --> | ||||||
|  |     <div v-else-if="objData.type === 'video'"> | ||||||
|  |       <!-- 列表 --> | ||||||
|  |       <el-table v-loading="loading" :data="list"> | ||||||
|  |         <el-table-column label="编号" align="center" prop="mediaId" /> | ||||||
|  |         <el-table-column label="文件名" align="center" prop="name" /> | ||||||
|  |         <el-table-column label="标题" align="center" prop="title" /> | ||||||
|  |         <el-table-column label="介绍" align="center" prop="introduction" /> | ||||||
|  |         <el-table-column label="视频" align="center"> | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <WxVideoPlayer :url="scope.row.url" /> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |         <el-table-column label="上传时间" align="center" prop="createTime" width="180"> | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <span>{{ formatDate(scope.row.createTime) }}</span> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |         <el-table-column | ||||||
|  |           label="操作" | ||||||
|  |           align="center" | ||||||
|  |           fixed="right" | ||||||
|  |           class-name="small-padding fixed-width" | ||||||
|  |         > | ||||||
|  |           <template #default="scope"> | ||||||
|  |             <el-button type="text" @click="selectMaterialFun(scope.row)" | ||||||
|  |               >选择<Icon icon="akar-icons:circle-plus" /> | ||||||
|  |             </el-button> | ||||||
|  |           </template> | ||||||
|  |         </el-table-column> | ||||||
|  |       </el-table> | ||||||
|  |       <!-- 分页组件 --> | ||||||
|  |       <pagination | ||||||
|  |         v-show="total > 0" | ||||||
|  |         :total="total" | ||||||
|  |         v-model:page="queryParams.pageNo" | ||||||
|  |         v-model:limit="queryParams.pageSize" | ||||||
|  |         @pagination="getMaterialPageFun" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |     <!-- 类型:news --> | ||||||
|  |     <div v-else-if="objData.type === 'news'"> | ||||||
|  |       <div class="waterfall" v-loading="loading"> | ||||||
|  |         <div class="waterfall-item" v-for="item in list" :key="item.mediaId"> | ||||||
|  |           <div v-if="item.content && item.content.newsItem"> | ||||||
|  |             <WxNews :articles="item.content.newsItem" /> | ||||||
|  |             <el-row class="ope-row"> | ||||||
|  |               <el-button type="success" @click="selectMaterialFun(item)"> | ||||||
|  |                 选择<Icon icon="ep:circle-check" /> | ||||||
|  |               </el-button> | ||||||
|  |             </el-row> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <!-- 分页组件 --> | ||||||
|  |       <pagination | ||||||
|  |         v-show="total > 0" | ||||||
|  |         :total="total" | ||||||
|  |         v-model:page="queryParams.pageNo" | ||||||
|  |         v-model:limit="queryParams.pageSize" | ||||||
|  |         @pagination="getMaterialPageFun" | ||||||
|  |       /> | ||||||
|     </div> |     </div> | ||||||
|     <!-- 分页组件 --> |  | ||||||
|     <pagination |  | ||||||
|       v-show="total > 0" |  | ||||||
|       :total="total" |  | ||||||
|       v-model:page="queryParams.pageNo" |  | ||||||
|       v-model:limit="queryParams.pageSize" |  | ||||||
|       @pagination="getMaterialPageFun" |  | ||||||
|     /> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  | @ -173,7 +176,7 @@ export default defineComponent({ | ||||||
|     const newsTypeRef = ref(props.newsType) |     const newsTypeRef = ref(props.newsType) | ||||||
| 
 | 
 | ||||||
|     const selectMaterialFun = (item) => { |     const selectMaterialFun = (item) => { | ||||||
|       ctx.emit('selectMaterial', item) |       ctx.emit('select-material', item) | ||||||
|     } |     } | ||||||
|     /** 搜索按钮操作 */ |     /** 搜索按钮操作 */ | ||||||
|     const handleQuery = () => { |     const handleQuery = () => { | ||||||
|  | @ -203,9 +206,10 @@ export default defineComponent({ | ||||||
|       total.value = data.total |       total.value = data.total | ||||||
|       loading.value = false |       loading.value = false | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     const getFreePublishPageFun = async () => { |     const getFreePublishPageFun = async () => { | ||||||
|       let data = await getFreePublishPage(queryParams) |       let data = await getFreePublishPage(queryParams) | ||||||
|       data.list.foreach((item) => { |       data.list.forEach((item) => { | ||||||
|         const newsItem = item.content.newsItem |         const newsItem = item.content.newsItem | ||||||
|         newsItem.forEach((article) => { |         newsItem.forEach((article) => { | ||||||
|           article.picUrl = article.thumbUrl |           article.picUrl = article.thumbUrl | ||||||
|  | @ -232,6 +236,7 @@ export default defineComponent({ | ||||||
|     onMounted(async () => { |     onMounted(async () => { | ||||||
|       getPage() |       getPage() | ||||||
|     }) |     }) | ||||||
|  | 
 | ||||||
|     return { |     return { | ||||||
|       handleQuery, |       handleQuery, | ||||||
|       dateFormatter, |       dateFormatter, | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ | ||||||
|       <div class="select-item" v-if="objDataRef.url"> |       <div class="select-item" v-if="objDataRef.url"> | ||||||
|         <img class="material-img" :src="objDataRef.url" /> |         <img class="material-img" :src="objDataRef.url" /> | ||||||
|         <p class="item-name" v-if="objDataRef.name">{{ objDataRef.name }}</p> |         <p class="item-name" v-if="objDataRef.name">{{ objDataRef.name }}</p> | ||||||
|         <el-row class="ope-row"> |         <el-row class="ope-row" justify="center"> | ||||||
|           <el-button type="danger" circle @click="deleteObj"> |           <el-button type="danger" circle @click="deleteObj"> | ||||||
|             <icon icon="ep:delete" /> |             <icon icon="ep:delete" /> | ||||||
|           </el-button> |           </el-button> | ||||||
|  | @ -52,7 +52,7 @@ | ||||||
|             <icon icon="ep:circle-check" /> |             <icon icon="ep:circle-check" /> | ||||||
|           </el-button> |           </el-button> | ||||||
|           <el-dialog title="选择图片" v-model="dialogImageVisible" width="90%" append-to-body> |           <el-dialog title="选择图片" v-model="dialogImageVisible" width="90%" append-to-body> | ||||||
|             <wx-material-select :obj-data="objDataRef" @selectMaterial="selectMaterial" /> |             <WxMaterialSelect :obj-data="objDataRef" @select-material="selectMaterial" /> | ||||||
|           </el-dialog> |           </el-dialog> | ||||||
|         </el-col> |         </el-col> | ||||||
|         <!-- 文件上传 --> |         <!-- 文件上传 --> | ||||||
|  | @ -91,20 +91,20 @@ | ||||||
|       <div class="select-item2" v-if="objDataRef.url"> |       <div class="select-item2" v-if="objDataRef.url"> | ||||||
|         <p class="item-name">{{ objDataRef.name }}</p> |         <p class="item-name">{{ objDataRef.name }}</p> | ||||||
|         <div class="item-infos"> |         <div class="item-infos"> | ||||||
|           <wx-voice-player :url="objDataRef.url" /> |           <WxVoicePlayer :url="objDataRef.url" /> | ||||||
|         </div> |         </div> | ||||||
|         <el-row class="ope-row"> |         <el-row class="ope-row" justify="center"> | ||||||
|           <el-button type="danger" icon="el-icon-delete" circle @click="deleteObj" /> |           <el-button type="danger" circle @click="deleteObj"><Icon icon="ep:delete" /></el-button> | ||||||
|         </el-row> |         </el-row> | ||||||
|       </div> |       </div> | ||||||
|       <el-row v-else style="text-align: center"> |       <el-row v-else style="text-align: center"> | ||||||
|         <!-- 选择素材 --> |         <!-- 选择素材 --> | ||||||
|         <el-col :span="12" class="col-select"> |         <el-col :span="12" class="col-select"> | ||||||
|           <el-button type="success" @click="openMaterial"> |           <el-button type="success" @click="openMaterial"> | ||||||
|             素材库选择<i class="el-icon-circle-check el-icon--right"></i> |             素材库选择<Icon icon="ep:circle-check" /> | ||||||
|           </el-button> |           </el-button> | ||||||
|           <el-dialog title="选择语音" v-model="dialogVoiceVisible" width="90%" append-to-body> |           <el-dialog title="选择语音" v-model="dialogVoiceVisible" width="90%" append-to-body> | ||||||
|             <WxMaterialSelect :objData="objData" @selectMaterial="selectMaterial" /> |             <WxMaterialSelect :objData="objData" @select-material="selectMaterial" /> | ||||||
|           </el-dialog> |           </el-dialog> | ||||||
|         </el-col> |         </el-col> | ||||||
|         <!-- 文件上传 --> |         <!-- 文件上传 --> | ||||||
|  | @ -151,7 +151,7 @@ | ||||||
|           @input="inputContent" |           @input="inputContent" | ||||||
|         /> |         /> | ||||||
|         <div style="text-align: center"> |         <div style="text-align: center"> | ||||||
|           <wx-video-player v-if="objDataRef.url" :url="objDataRef.url" /> |           <WxVideoPlayer v-if="objDataRef.url" :url="objDataRef.url" /> | ||||||
|         </div> |         </div> | ||||||
|         <el-col> |         <el-col> | ||||||
|           <el-row style="text-align: center" align="middle"> |           <el-row style="text-align: center" align="middle"> | ||||||
|  | @ -162,7 +162,7 @@ | ||||||
|                 <icon icon="ep:circle-check" /> |                 <icon icon="ep:circle-check" /> | ||||||
|               </el-button> |               </el-button> | ||||||
|               <el-dialog title="选择视频" v-model="dialogVideoVisible" width="90%" append-to-body> |               <el-dialog title="选择视频" v-model="dialogVideoVisible" width="90%" append-to-body> | ||||||
|                 <wx-material-select :objData="objDataRef" @selectMaterial="selectMaterial" /> |                 <WxMaterialSelect :objData="objDataRef" @select-material="selectMaterial" /> | ||||||
|               </el-dialog> |               </el-dialog> | ||||||
|             </el-col> |             </el-col> | ||||||
|             <!-- 文件上传 --> |             <!-- 文件上传 --> | ||||||
|  | @ -196,8 +196,8 @@ | ||||||
|         </el-row> |         </el-row> | ||||||
|       </template> |       </template> | ||||||
|       <el-row> |       <el-row> | ||||||
|         <div class="select-item" v-if="objDataRef.articles.size > 0"> |         <div class="select-item" v-if="objDataRef.articles?.length > 0"> | ||||||
|           <wx-news :articles="objDataRef.articles" /> |           <WxNews :articles="objDataRef.articles" /> | ||||||
|           <el-col class="ope-row"> |           <el-col class="ope-row"> | ||||||
|             <el-button type="danger" circle @click="deleteObj"> |             <el-button type="danger" circle @click="deleteObj"> | ||||||
|               <icon icon="ep:delete" /> |               <icon icon="ep:delete" /> | ||||||
|  | @ -216,9 +216,9 @@ | ||||||
|           </el-row> |           </el-row> | ||||||
|         </el-col> |         </el-col> | ||||||
|         <el-dialog title="选择图文" v-model="dialogNewsVisible" width="90%" append-to-body> |         <el-dialog title="选择图文" v-model="dialogNewsVisible" width="90%" append-to-body> | ||||||
|           <wx-material-select |           <WxMaterialSelect | ||||||
|             :objData="objDataRef" |             :objData="objDataRef" | ||||||
|             @selectMaterial="selectMaterial" |             @select-material="selectMaterial" | ||||||
|             :newsType="newsType" |             :newsType="newsType" | ||||||
|           /> |           /> | ||||||
|         </el-dialog> |         </el-dialog> | ||||||
|  | @ -268,9 +268,9 @@ | ||||||
|             </el-col> |             </el-col> | ||||||
|           </el-row> |           </el-row> | ||||||
|           <el-dialog title="选择图片" v-model="dialogThumbVisible" width="80%" append-to-body> |           <el-dialog title="选择图片" v-model="dialogThumbVisible" width="80%" append-to-body> | ||||||
|             <wx-material-select |             <WxMaterialSelect | ||||||
|               :objData="{ type: 'image', accountId: objDataRef.accountId }" |               :objData="{ type: 'image', accountId: objDataRef.accountId }" | ||||||
|               @selectMaterial="selectMaterial" |               @select-material="selectMaterial" | ||||||
|             /> |             /> | ||||||
|           </el-dialog> |           </el-dialog> | ||||||
|         </el-col> |         </el-col> | ||||||
|  | @ -482,7 +482,7 @@ export default defineComponent({ | ||||||
|       // 创建 tempObjItem 对象,并设置对应的值 |       // 创建 tempObjItem 对象,并设置对应的值 | ||||||
|       let tempObjItem = { |       let tempObjItem = { | ||||||
|         type: '', |         type: '', | ||||||
|         articles: '', |         articles: [], | ||||||
|         thumbMediaId: '', |         thumbMediaId: '', | ||||||
|         thumbMediaUrl: '', |         thumbMediaUrl: '', | ||||||
|         introduction: '', |         introduction: '', | ||||||
|  | @ -560,7 +560,7 @@ export default defineComponent({ | ||||||
|     } |     } | ||||||
|     const deleteObj = () => { |     const deleteObj = () => { | ||||||
|       if (objDataRef.type === 'news') { |       if (objDataRef.type === 'news') { | ||||||
|         objDataRef.articles = '' |         objDataRef.articles = [] | ||||||
|       } else if (objDataRef.type === 'image') { |       } else if (objDataRef.type === 'image') { | ||||||
|         objDataRef.mediaId = null |         objDataRef.mediaId = null | ||||||
|         objDataRef.url = null |         objDataRef.url = null | ||||||
|  |  | ||||||
|  | @ -1,3 +1,821 @@ | ||||||
| <template> | <template> | ||||||
|   <span>开发中</span> |   <div class="app-container"> | ||||||
|  |     <doc-alert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" /> | ||||||
|  | 
 | ||||||
|  |     <!-- 搜索工作栏 --> | ||||||
|  |     <el-form :model="queryParams" ref="queryFormRef" size="small" :inline="true" label-width="68px"> | ||||||
|  |       <el-form-item label="公众号" prop="accountId"> | ||||||
|  |         <el-select v-model="queryParams.accountId" placeholder="请选择公众号"> | ||||||
|  |           <el-option | ||||||
|  |             v-for="item in accountList" | ||||||
|  |             :key="parseInt(item.id)" | ||||||
|  |             :label="item.name" | ||||||
|  |             :value="parseInt(item.id)" | ||||||
|  |           /> | ||||||
|  |         </el-select> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item> | ||||||
|  |         <el-button type="primary" @click="handleQuery"><Icon icon="ep:search" />搜索</el-button> | ||||||
|  |         <el-button @click="resetQuery"><Icon icon="ep:refresh" />重置</el-button> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  | 
 | ||||||
|  |     <!-- 操作工具栏 --> | ||||||
|  |     <el-row :gutter="10" class="mb8"> | ||||||
|  |       <el-col :span="1.5"> | ||||||
|  |         <el-button | ||||||
|  |           type="primary" | ||||||
|  |           plain | ||||||
|  |           size="small" | ||||||
|  |           @click="handleAdd" | ||||||
|  |           v-hasPermi="['mp:draft:create']" | ||||||
|  |           ><Icon icon="ep:plus" />新增 | ||||||
|  |         </el-button> | ||||||
|  |       </el-col> | ||||||
|  |     </el-row> | ||||||
|  | 
 | ||||||
|  |     <!-- 列表 --> | ||||||
|  |     <div class="waterfall" v-loading="loading"> | ||||||
|  |       <template v-for="item in list" :key="item.articleId"> | ||||||
|  |         <div class="waterfall-item" v-if="item.content && item.content.newsItem"> | ||||||
|  |           <wx-news :articles="item.content.newsItem" /> | ||||||
|  |           <!-- 操作按钮 --> | ||||||
|  |           <el-row class="ope-row"> | ||||||
|  |             <el-button | ||||||
|  |               type="success" | ||||||
|  |               circle | ||||||
|  |               @click="handlePublish(item)" | ||||||
|  |               v-hasPermi="['mp:free-publish:submit']" | ||||||
|  |               ><Icon icon="fa:upload" | ||||||
|  |             /></el-button> | ||||||
|  |             <el-button | ||||||
|  |               type="primary" | ||||||
|  |               circle | ||||||
|  |               @click="handleUpdate(item)" | ||||||
|  |               v-hasPermi="['mp:draft:update']" | ||||||
|  |               ><Icon icon="ep:edit" | ||||||
|  |             /></el-button> | ||||||
|  |             <el-button | ||||||
|  |               type="danger" | ||||||
|  |               circle | ||||||
|  |               @click="handleDelete(item)" | ||||||
|  |               v-hasPermi="['mp:draft:delete']" | ||||||
|  |               ><Icon icon="ep:delete" | ||||||
|  |             /></el-button> | ||||||
|  |           </el-row> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </div> | ||||||
|  |     <!-- 分页记录 --> | ||||||
|  |     <pagination | ||||||
|  |       v-show="total > 0" | ||||||
|  |       :total="total" | ||||||
|  |       v-model:page="queryParams.pageNo" | ||||||
|  |       v-model:limit="queryParams.pageSize" | ||||||
|  |       @pagination="getList" | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <!-- 添加或修改草稿对话框 --> | ||||||
|  |     <Teleport to="body"> | ||||||
|  |       <el-dialog | ||||||
|  |         :title="operateMaterial === 'add' ? '新建图文' : '修改图文'" | ||||||
|  |         width="80%" | ||||||
|  |         top="20px" | ||||||
|  |         v-model="dialogNewsVisible" | ||||||
|  |         :before-close="dialogNewsClose" | ||||||
|  |         :close-on-click-modal="false" | ||||||
|  |       > | ||||||
|  |         <div class="left"> | ||||||
|  |           <div class="select-item"> | ||||||
|  |             <div v-for="(news, index) in articlesAdd" :key="news.id"> | ||||||
|  |               <div | ||||||
|  |                 class="news-main father" | ||||||
|  |                 v-if="index === 0" | ||||||
|  |                 :class="{ activeAddNews: isActiveAddNews === index }" | ||||||
|  |                 @click="activeNews(index)" | ||||||
|  |               > | ||||||
|  |                 <div class="news-content"> | ||||||
|  |                   <img class="material-img" v-if="news.thumbUrl" :src="news.thumbUrl" /> | ||||||
|  |                   <div class="news-content-title">{{ news.title }}</div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="child" v-if="articlesAdd.length > 1"> | ||||||
|  |                   <el-button size="small" @click="downNews(index)" | ||||||
|  |                     ><Icon icon="ep:sort-down" />下移</el-button | ||||||
|  |                   > | ||||||
|  |                   <el-button v-if="operateMaterial === 'add'" size="small" @click="minusNews(index)" | ||||||
|  |                     ><Icon icon="ep:delete" />删除 | ||||||
|  |                   </el-button> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |               <div | ||||||
|  |                 class="news-main-item father" | ||||||
|  |                 v-if="index > 0" | ||||||
|  |                 :class="{ activeAddNews: isActiveAddNews === index }" | ||||||
|  |                 @click="activeNews(index)" | ||||||
|  |               > | ||||||
|  |                 <div class="news-content-item"> | ||||||
|  |                   <div class="news-content-item-title">{{ news.title }}</div> | ||||||
|  |                   <div class="news-content-item-img"> | ||||||
|  |                     <img | ||||||
|  |                       class="material-img" | ||||||
|  |                       v-if="news.thumbUrl" | ||||||
|  |                       :src="news.thumbUrl" | ||||||
|  |                       height="100%" | ||||||
|  |                     /> | ||||||
|  |                   </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="child"> | ||||||
|  |                   <el-button | ||||||
|  |                     v-if="articlesAdd.length > index + 1" | ||||||
|  |                     size="small" | ||||||
|  |                     @click="downNews(index)" | ||||||
|  |                     ><Icon icon="ep:sort-down" />下移 | ||||||
|  |                   </el-button> | ||||||
|  |                   <el-button size="small" @click="upNews(index)" | ||||||
|  |                     ><Icon icon="ep:sort-up" />上移</el-button | ||||||
|  |                   > | ||||||
|  |                   <el-button | ||||||
|  |                     v-if="operateMaterial === 'add'" | ||||||
|  |                     type="danger" | ||||||
|  |                     size="small" | ||||||
|  |                     @click="minusNews(index)" | ||||||
|  |                     ><Icon icon="ep:delete" />删除 | ||||||
|  |                   </el-button> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <el-row justify="center" class="ope-row"> | ||||||
|  |               <el-button | ||||||
|  |                 type="primary" | ||||||
|  |                 circle | ||||||
|  |                 @click="plusNews(item)" | ||||||
|  |                 v-if="articlesAdd.length < 8 && operateMaterial === 'add'" | ||||||
|  |               > | ||||||
|  |                 <Icon icon="ep:plus" /> | ||||||
|  |               </el-button> | ||||||
|  |             </el-row> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="right" v-loading="addMaterialLoading" v-if="articlesAdd.length > 0"> | ||||||
|  |           <br /> | ||||||
|  |           <br /> | ||||||
|  |           <br /> | ||||||
|  |           <br /> | ||||||
|  |           <!-- 标题、作者、原文地址 --> | ||||||
|  |           <el-input v-model="articlesAdd[isActiveAddNews].title" placeholder="请输入标题(必填)" /> | ||||||
|  |           <el-input | ||||||
|  |             v-model="articlesAdd[isActiveAddNews].author" | ||||||
|  |             placeholder="请输入作者" | ||||||
|  |             style="margin-top: 5px" | ||||||
|  |           /> | ||||||
|  |           <el-input | ||||||
|  |             v-model="articlesAdd[isActiveAddNews].contentSourceUrl" | ||||||
|  |             placeholder="请输入原文地址" | ||||||
|  |             style="margin-top: 5px" | ||||||
|  |           /> | ||||||
|  |           <!-- 封面和摘要 --> | ||||||
|  |           <div class="input-tt">封面和摘要:</div> | ||||||
|  |           <div> | ||||||
|  |             <div class="thumb-div"> | ||||||
|  |               <img | ||||||
|  |                 class="material-img" | ||||||
|  |                 v-if="articlesAdd[isActiveAddNews].thumbUrl" | ||||||
|  |                 :src="articlesAdd[isActiveAddNews].thumbUrl" | ||||||
|  |                 :class="isActiveAddNews === 0 ? 'avatar' : 'avatar1'" | ||||||
|  |               /> | ||||||
|  |               <Icon | ||||||
|  |                 v-else | ||||||
|  |                 icon="ep:plus" | ||||||
|  |                 class="avatar-uploader-icon" | ||||||
|  |                 :class="isActiveAddNews === 0 ? 'avatar' : 'avatar1'" | ||||||
|  |               /> | ||||||
|  |               <div class="thumb-but"> | ||||||
|  |                 <el-upload | ||||||
|  |                   :action="actionUrl" | ||||||
|  |                   :headers="headers" | ||||||
|  |                   multiple | ||||||
|  |                   :limit="1" | ||||||
|  |                   :file-list="fileList" | ||||||
|  |                   :data="uploadData" | ||||||
|  |                   :before-upload="beforeThumbImageUpload" | ||||||
|  |                   :on-success="handleUploadSuccess" | ||||||
|  |                 > | ||||||
|  |                   <template #trigger> | ||||||
|  |                     <el-button size="small" type="primary">本地上传</el-button> | ||||||
|  |                   </template> | ||||||
|  |                   <el-button | ||||||
|  |                     size="small" | ||||||
|  |                     type="primary" | ||||||
|  |                     @click="openMaterial" | ||||||
|  |                     style="margin-left: 5px" | ||||||
|  |                     >素材库选择</el-button | ||||||
|  |                   > | ||||||
|  |                   <template #tip> | ||||||
|  |                     <div class="el-upload__tip">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</div> | ||||||
|  |                   </template> | ||||||
|  |                 </el-upload> | ||||||
|  |               </div> | ||||||
|  |               <Teleport to="body"> | ||||||
|  |                 <el-dialog title="选择图片" v-model="dialogImageVisible" width="80%"> | ||||||
|  |                   <WxMaterialSelect | ||||||
|  |                     ref="materialSelectRef" | ||||||
|  |                     :objData="{ type: 'image', accountId: queryParams.accountId }" | ||||||
|  |                     @select-material="selectMaterial" | ||||||
|  |                   /> | ||||||
|  |                 </el-dialog> | ||||||
|  |               </Teleport> | ||||||
|  |             </div> | ||||||
|  |             <el-input | ||||||
|  |               :rows="8" | ||||||
|  |               type="textarea" | ||||||
|  |               v-model="articlesAdd[isActiveAddNews].digest" | ||||||
|  |               placeholder="请输入摘要" | ||||||
|  |               class="digest" | ||||||
|  |               maxlength="120" | ||||||
|  |               style="float: right" | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |           <!--富文本编辑器组件--> | ||||||
|  |           <el-row> | ||||||
|  |             <wx-editor | ||||||
|  |               v-model="articlesAdd[isActiveAddNews].content" | ||||||
|  |               :account-id="uploadData.accountId" | ||||||
|  |               v-if="hackResetEditor" | ||||||
|  |             /> | ||||||
|  |           </el-row> | ||||||
|  |         </div> | ||||||
|  |         <template #footer> | ||||||
|  |           <div class="dialog-footer"> | ||||||
|  |             <el-button @click="dialogNewsVisible = false">取 消</el-button> | ||||||
|  |             <el-button type="primary" @click="submitForm">提 交</el-button> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |       </el-dialog> | ||||||
|  |     </Teleport> | ||||||
|  |   </div> | ||||||
| </template> | </template> | ||||||
|  | 
 | ||||||
|  | <script setup name="MpDraft"> | ||||||
|  | import { ref, onMounted, reactive, nextTick } from 'vue' | ||||||
|  | import WxEditor from '@/views/mp/components/wx-editor/WxEditor.vue' | ||||||
|  | import WxNews from '@/views/mp/components/wx-news/main.vue' | ||||||
|  | import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue' | ||||||
|  | import { getAccessToken } from '@/utils/auth' | ||||||
|  | import { createDraft, deleteDraft, getDraftPage, updateDraft } from '@/api/mp/draft' | ||||||
|  | import { getSimpleAccountList } from '@/api/mp/account' | ||||||
|  | import { submitFreePublish } from '@/api/mp/freePublish' | ||||||
|  | // 可以用改本地数据模拟,避免API调用超限 | ||||||
|  | // import drafts from './mock' | ||||||
|  | 
 | ||||||
|  | const BASE_URL = import.meta.env.VITE_BASE_URL | ||||||
|  | 
 | ||||||
|  | const message = useMessage() | ||||||
|  | 
 | ||||||
|  | const materialSelectRef = ref() | ||||||
|  | const queryFormRef = ref() | ||||||
|  | 
 | ||||||
|  | // 遮罩层 | ||||||
|  | const loading = ref(false) | ||||||
|  | // 显示搜索条件 | ||||||
|  | // 总条数 | ||||||
|  | const total = ref(0) | ||||||
|  | // 数据列表 | ||||||
|  | const list = ref([]) | ||||||
|  | const queryParams = reactive({ | ||||||
|  |   pageNo: 1, | ||||||
|  |   pageSize: 10, | ||||||
|  |   accountId: undefined | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // ========== 文件上传 ========== | ||||||
|  | const actionUrl = ref(BASE_URL + '/admin-api/mp/material/upload-permanent') // 上传永久素材的地址 | ||||||
|  | const headers = ref({ Authorization: 'Bearer ' + getAccessToken() }) // 设置上传的请求头部 | ||||||
|  | const fileList = ref([]) | ||||||
|  | const uploadData = reactive({ | ||||||
|  |   type: 'image', | ||||||
|  |   accountId: 1 | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // ========== 草稿新建 or 修改 ========== | ||||||
|  | const dialogNewsVisible = ref(false) | ||||||
|  | const addMaterialLoading = ref(false) // 添加草稿的 loading 标识 | ||||||
|  | const articlesAdd = ref([]) | ||||||
|  | const isActiveAddNews = ref(0) | ||||||
|  | const dialogImageVisible = ref(false) | ||||||
|  | const operateMaterial = ref('add') | ||||||
|  | const articlesMediaId = ref('') | ||||||
|  | const hackResetEditor = ref(false) | ||||||
|  | // 公众号账号列表 | ||||||
|  | const accountList = ref([]) | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  |   accountList.value = await getSimpleAccountList() | ||||||
|  |   // 选中第一个 | ||||||
|  |   if (accountList.value.length > 0) { | ||||||
|  |     // @ts-ignore | ||||||
|  |     queryParams.accountId = accountList.value[0].id | ||||||
|  |   } | ||||||
|  |   await getList() | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // ======================== 列表查询 ======================== | ||||||
|  | /** 设置账号编号 */ | ||||||
|  | const setAccountId = (accountId) => { | ||||||
|  |   queryParams.accountId = accountId | ||||||
|  |   uploadData.accountId = accountId | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查询列表 */ | ||||||
|  | const getList = async () => { | ||||||
|  |   // 如果没有选中公众号账号,则进行提示。 | ||||||
|  |   if (!queryParams.accountId) { | ||||||
|  |     message.error('未选中公众号,无法查询草稿箱') | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   loading.value = true | ||||||
|  |   try { | ||||||
|  |     const drafts = await getDraftPage(queryParams) | ||||||
|  |     drafts.list.forEach((item) => { | ||||||
|  |       const newsItem = item.content.newsItem | ||||||
|  |       // 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面 | ||||||
|  |       newsItem.forEach((article) => { | ||||||
|  |         article.picUrl = article.thumbUrl | ||||||
|  |       }) | ||||||
|  |     }) | ||||||
|  |     list.value = drafts.list | ||||||
|  |     total.value = drafts.total | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   queryParams.pageNo = 1 | ||||||
|  |   // 默认选中第一个 | ||||||
|  |   if (queryParams.accountId) { | ||||||
|  |     setAccountId(queryParams.accountId) | ||||||
|  |   } | ||||||
|  |   getList() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   queryFormRef.value.resetFields() | ||||||
|  |   // 默认选中第一个 | ||||||
|  |   if (accountList.value.length > 0) { | ||||||
|  |     setAccountId(accountList.value[0].id) | ||||||
|  |   } | ||||||
|  |   handleQuery() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 新增/修改草稿 ======================== | ||||||
|  | /** 新增按钮操作 */ | ||||||
|  | const handleAdd = () => { | ||||||
|  |   resetEditor() | ||||||
|  |   reset() | ||||||
|  |   // 打开表单,并设置初始化 | ||||||
|  |   operateMaterial.value = 'add' | ||||||
|  |   dialogNewsVisible.value = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 更新按钮操作 */ | ||||||
|  | const handleUpdate = (item) => { | ||||||
|  |   resetEditor() | ||||||
|  |   reset() | ||||||
|  |   articlesMediaId.value = item.mediaId | ||||||
|  |   articlesAdd.value = JSON.parse(JSON.stringify(item.content.newsItem)) | ||||||
|  |   // 打开表单,并设置初始化 | ||||||
|  |   operateMaterial.value = 'edit' | ||||||
|  |   dialogNewsVisible.value = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 提交按钮 */ | ||||||
|  | const submitForm = () => { | ||||||
|  |   addMaterialLoading.value = true | ||||||
|  |   if (operateMaterial.value === 'add') { | ||||||
|  |     createDraft(queryParams.accountId, articlesAdd.value) | ||||||
|  |       .then(() => { | ||||||
|  |         message.notifySuccess('新增成功') | ||||||
|  |         dialogNewsVisible.value = false | ||||||
|  |         getList() | ||||||
|  |       }) | ||||||
|  |       .finally(() => { | ||||||
|  |         addMaterialLoading.value = false | ||||||
|  |       }) | ||||||
|  |   } else { | ||||||
|  |     updateDraft(queryParams.accountId, articlesMediaId.value, articlesAdd.value) | ||||||
|  |       .then(() => { | ||||||
|  |         message.notifySuccess('更新成功') | ||||||
|  |         dialogNewsVisible.value = false | ||||||
|  |         getList() | ||||||
|  |       }) | ||||||
|  |       .finally(() => { | ||||||
|  |         addMaterialLoading.value = false | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 关闭弹窗 | ||||||
|  | const dialogNewsClose = async (done) => { | ||||||
|  |   try { | ||||||
|  |     await message.confirm('修改内容可能还未保存,确定关闭吗?') | ||||||
|  |     reset() | ||||||
|  |     resetEditor() | ||||||
|  |     done() | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 表单重置 | ||||||
|  | const reset = () => { | ||||||
|  |   isActiveAddNews.value = 0 | ||||||
|  |   articlesAdd.value = [buildEmptyArticle()] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 表单 Editor 重置 | ||||||
|  | const resetEditor = () => { | ||||||
|  |   hackResetEditor.value = false // 销毁组件 | ||||||
|  |   nextTick(() => { | ||||||
|  |     hackResetEditor.value = true // 重建组件 | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 将图文向下移动 | ||||||
|  | const downNews = (index) => { | ||||||
|  |   let temp = articlesAdd.value[index] | ||||||
|  |   articlesAdd.value[index] = articlesAdd.value[index + 1] | ||||||
|  |   articlesAdd.value[index + 1] = temp | ||||||
|  |   isActiveAddNews.value = index + 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 将图文向上移动 | ||||||
|  | const upNews = (index) => { | ||||||
|  |   let temp = articlesAdd.value[index] | ||||||
|  |   articlesAdd.value[index] = articlesAdd.value[index - 1] | ||||||
|  |   articlesAdd.value[index - 1] = temp | ||||||
|  |   isActiveAddNews.value = index - 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 选中指定 index 的图文 | ||||||
|  | const activeNews = (index) => { | ||||||
|  |   resetEditor() | ||||||
|  |   isActiveAddNews.value = index | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 删除指定 index 的图文 | ||||||
|  | const minusNews = async (index) => { | ||||||
|  |   try { | ||||||
|  |     await message.confirm('确定删除该图文吗?') | ||||||
|  |     articlesAdd.value.splice(index, 1) | ||||||
|  |     if (isActiveAddNews.value === index) { | ||||||
|  |       isActiveAddNews.value = 0 | ||||||
|  |     } | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 添加一个图文 | ||||||
|  | const plusNews = () => { | ||||||
|  |   articlesAdd.value.push(buildEmptyArticle()) | ||||||
|  |   isActiveAddNews.value = articlesAdd.value.length - 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 创建空的 article | ||||||
|  | const buildEmptyArticle = () => { | ||||||
|  |   return { | ||||||
|  |     title: '', | ||||||
|  |     thumbMediaId: '', | ||||||
|  |     author: '', | ||||||
|  |     digest: '', | ||||||
|  |     showCoverPic: '', | ||||||
|  |     content: '', | ||||||
|  |     contentSourceUrl: '', | ||||||
|  |     needOpenComment: '', | ||||||
|  |     onlyFansCanComment: '', | ||||||
|  |     thumbUrl: '' | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 文件上传 ======================== | ||||||
|  | const beforeThumbImageUpload = (file) => { | ||||||
|  |   addMaterialLoading.value = true | ||||||
|  |   const isType = | ||||||
|  |     file.type === 'image/jpeg' || | ||||||
|  |     file.type === 'image/png' || | ||||||
|  |     file.type === 'image/gif' || | ||||||
|  |     file.type === 'image/bmp' || | ||||||
|  |     file.type === 'image/jpg' | ||||||
|  |   if (!isType) { | ||||||
|  |     message.error('上传图片格式不对!') | ||||||
|  |     addMaterialLoading.value = false | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  |   const isLt = file.size / 1024 / 1024 < 2 | ||||||
|  |   if (!isLt) { | ||||||
|  |     message.error('上传图片大小不能超过 2M!') | ||||||
|  |     addMaterialLoading.value = false | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  |   // 校验通过 | ||||||
|  |   return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const handleUploadSuccess = (response, file, fileList) => { | ||||||
|  |   addMaterialLoading.value = false | ||||||
|  |   if (response.code !== 0) { | ||||||
|  |     message.error('上传出错:' + response.msg) | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // 重置上传文件的表单 | ||||||
|  |   fileList.value = [] | ||||||
|  | 
 | ||||||
|  |   // 设置草稿的封面字段 | ||||||
|  |   articlesAdd.value[isActiveAddNews.value].thumbMediaId = response.data.mediaId | ||||||
|  |   articlesAdd.value[isActiveAddNews.value].thumbUrl = response.data.url | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 选择 or 上传完素材,设置回草稿 | ||||||
|  | const selectMaterial = (item) => { | ||||||
|  |   dialogImageVisible.value = false | ||||||
|  |   articlesAdd.value[isActiveAddNews.value].thumbMediaId = item.mediaId | ||||||
|  |   articlesAdd.value[isActiveAddNews.value].thumbUrl = item.url | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 打开素材选择 | ||||||
|  | const openMaterial = () => { | ||||||
|  |   dialogImageVisible.value = true | ||||||
|  |   try { | ||||||
|  |     materialSelectRef.value.queryParams.accountId = queryParams.accountId // 强制设置下 accountId,避免二次查询不对 | ||||||
|  |     materialSelectRef.value.handleQuery() // 刷新列表,失败也无所谓 | ||||||
|  |   } catch (e) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 草稿箱发布 ======================== | ||||||
|  | const handlePublish = async (item) => { | ||||||
|  |   const accountId = queryParams.accountId | ||||||
|  |   const mediaId = item.mediaId | ||||||
|  |   const content = | ||||||
|  |     '你正在通过发布的方式发表内容。 发布不占用群发次数,一天可多次发布。已发布内容不会推送给用户,也不会展示在公众号主页中。 发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。' | ||||||
|  |   try { | ||||||
|  |     await message.confirm(content) | ||||||
|  |     await submitFreePublish(accountId, mediaId) | ||||||
|  |     getList() | ||||||
|  |     message.notifySuccess('发布成功') | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const handleDelete = async (item) => { | ||||||
|  |   const accountId = queryParams.accountId | ||||||
|  |   const mediaId = item.mediaId | ||||||
|  |   try { | ||||||
|  |     await message.confirm('此操作将永久删除该草稿, 是否继续?') | ||||||
|  |     await deleteDraft(accountId, mediaId) | ||||||
|  |     getList() | ||||||
|  |     message.notifySuccess('删除成功') | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .pagination { | ||||||
|  |   float: right; | ||||||
|  |   margin-right: 25px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .add_but { | ||||||
|  |   padding: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ope-row { | ||||||
|  |   margin-top: 5px; | ||||||
|  |   text-align: center; | ||||||
|  |   border-top: 1px solid #eaeaea; | ||||||
|  |   padding-top: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .item-name { | ||||||
|  |   font-size: 12px; | ||||||
|  |   overflow: hidden; | ||||||
|  |   text-overflow: ellipsis; | ||||||
|  |   white-space: nowrap; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .el-upload__tip { | ||||||
|  |   margin-left: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*新增图文*/ | ||||||
|  | .left { | ||||||
|  |   display: inline-block; | ||||||
|  |   width: 35%; | ||||||
|  |   vertical-align: top; | ||||||
|  |   margin-top: 200px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .right { | ||||||
|  |   display: inline-block; | ||||||
|  |   width: 60%; | ||||||
|  |   margin-top: -40px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar-uploader { | ||||||
|  |   width: 20%; | ||||||
|  |   display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar-uploader .el-upload { | ||||||
|  |   border-radius: 6px; | ||||||
|  |   cursor: pointer; | ||||||
|  |   position: relative; | ||||||
|  |   overflow: hidden; | ||||||
|  |   text-align: unset !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar-uploader .el-upload:hover { | ||||||
|  |   border-color: #165dff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar-uploader-icon { | ||||||
|  |   border: 1px solid #d9d9d9; | ||||||
|  |   font-size: 28px; | ||||||
|  |   color: #8c939d; | ||||||
|  |   width: 120px; | ||||||
|  |   height: 120px; | ||||||
|  |   line-height: 120px; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar { | ||||||
|  |   width: 230px; | ||||||
|  |   height: 120px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .avatar1 { | ||||||
|  |   width: 120px; | ||||||
|  |   height: 120px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .digest { | ||||||
|  |   width: 60%; | ||||||
|  |   display: inline-block; | ||||||
|  |   vertical-align: top; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*新增图文*/ | ||||||
|  | /*瀑布流样式*/ | ||||||
|  | .waterfall { | ||||||
|  |   width: 100%; | ||||||
|  |   column-gap: 10px; | ||||||
|  |   column-count: 5; | ||||||
|  |   margin: 0 auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .waterfall-item { | ||||||
|  |   padding: 10px; | ||||||
|  |   margin-bottom: 10px; | ||||||
|  |   break-inside: avoid; | ||||||
|  |   border: 1px solid #eaeaea; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | p { | ||||||
|  |   line-height: 30px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 992px) and (max-width: 1300px) { | ||||||
|  |   .waterfall { | ||||||
|  |     column-count: 3; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   p { | ||||||
|  |     color: red; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 768px) and (max-width: 991px) { | ||||||
|  |   .waterfall { | ||||||
|  |     column-count: 2; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   p { | ||||||
|  |     color: orange; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (max-width: 767px) { | ||||||
|  |   .waterfall { | ||||||
|  |     column-count: 1; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*瀑布流样式*/ | ||||||
|  | .news-main { | ||||||
|  |   background-color: #ffffff; | ||||||
|  |   width: 100%; | ||||||
|  |   margin: auto; | ||||||
|  |   height: 120px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-content { | ||||||
|  |   background-color: #acadae; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 120px; | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-content-title { | ||||||
|  |   display: inline-block; | ||||||
|  |   font-size: 15px; | ||||||
|  |   color: #ffffff; | ||||||
|  |   position: absolute; | ||||||
|  |   left: 0px; | ||||||
|  |   bottom: 0px; | ||||||
|  |   background-color: black; | ||||||
|  |   width: 98%; | ||||||
|  |   padding: 1%; | ||||||
|  |   opacity: 0.65; | ||||||
|  |   overflow: hidden; | ||||||
|  |   text-overflow: ellipsis; | ||||||
|  |   white-space: nowrap; | ||||||
|  |   height: 25px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-main-item { | ||||||
|  |   background-color: #ffffff; | ||||||
|  |   padding: 5px 0px; | ||||||
|  |   border-top: 1px solid #eaeaea; | ||||||
|  |   width: 100%; | ||||||
|  |   margin: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-content-item { | ||||||
|  |   position: relative; | ||||||
|  |   margin-left: -3px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-content-item-title { | ||||||
|  |   display: inline-block; | ||||||
|  |   font-size: 12px; | ||||||
|  |   width: 70%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-content-item-img { | ||||||
|  |   display: inline-block; | ||||||
|  |   width: 25%; | ||||||
|  |   background-color: #acadae; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .input-tt { | ||||||
|  |   padding: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .activeAddNews { | ||||||
|  |   border: 5px solid #2bb673; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .news-main-plus { | ||||||
|  |   width: 280px; | ||||||
|  |   text-align: center; | ||||||
|  |   margin: auto; | ||||||
|  |   height: 50px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .icon-plus { | ||||||
|  |   margin: 10px; | ||||||
|  |   font-size: 25px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .select-item { | ||||||
|  |   width: 60%; | ||||||
|  |   padding: 10px; | ||||||
|  |   margin: 0 auto 10px auto; | ||||||
|  |   border: 1px solid #eaeaea; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .father .child { | ||||||
|  |   display: none; | ||||||
|  |   text-align: center; | ||||||
|  |   position: relative; | ||||||
|  |   bottom: 25px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .father:hover .child { | ||||||
|  |   display: block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .thumb-div { | ||||||
|  |   display: inline-block; | ||||||
|  |   width: 30%; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .thumb-but { | ||||||
|  |   margin: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .material-img { | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,151 @@ | ||||||
|  | export default { | ||||||
|  |   list: [ | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-q-G9pdsmZw0OYG4FzHQkKfpLfEwIH51wy2bxisx8PvW', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: '我是标题(OOO)', | ||||||
|  |             author: '我是作者', | ||||||
|  |             digest: '我是摘要', | ||||||
|  |             content: '我是内容', | ||||||
|  |             contentSourceUrl: 'https://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9XaFphcmtJVFh3VEc4Q1MxQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuN2QxTE56SFBCYXc2RE9NcUxIeS1CQjJuUHhTWjBlN2VOeGRpRi1fZUhwN1FNQjdrQV9yRU9EU0hibHREZmZoVW5acnZrN3ZjaWsxejR3RGpKczBzTHFIM0dFNFZWVkpBc0dWWlAzUEhlVmpnfn4%3D&chksm=1f6354802814dd969ef83c0f3babe555c614270b30bc383beaf7ffd13b0257f0fe5ced9af694#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn.png' | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             title: '我是标题(XXX)', | ||||||
|  |             author: '我是作者', | ||||||
|  |             digest: '我是摘要', | ||||||
|  |             content: '我是内容', | ||||||
|  |             contentSourceUrl: 'https://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9yTlYwOEs1clpwcE5OUEhCQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuN0NSMjFqN3N1aUZMbFNVLTZHN2ZDME9qOGp2THk2RFNlSTlKZ3Y1czFVZDdQQm5IeUg3dEppSUtpQUh5SExOOTRkT3dHNUdBdHdWSWlOendlREV3dS1jUEVQbFpiVTZmVW5iRWhZcGdkNTFRfn4%3D&chksm=1f6354802814dd96a403151cd44c7da4eecf0e475d25423e46ecd795b513bafd829a75daef9b#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn.png' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673655730 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-jGpXnO73ihN0lsNXknCRQHapp2xgHMRxHKG50LituFe', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: '我是标题(修改)', | ||||||
|  |             author: '我是作者', | ||||||
|  |             digest: '我是摘要', | ||||||
|  |             content: '我是内容', | ||||||
|  |             contentSourceUrl: 'https://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl95WVFXYndIZnZJd0t5cjgvQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuN1dlNURPbWswbEF4RDd5dVJTdjQ4cm9Cc0Q1TWhpMUh6SE1hVEE3ZHljaHhlZjZYSGF5N2JNSHpDTlh6ajNZbkpGTGpTcUQ4M3NMdW41ZUpXNFZZQ1VKbVlaMVp5ekxEV1czREdsY1dOYTZnfn4%3D&chksm=1f6354be2814dda8e6238037c2ebd52b1c8e80e93249a861ad80e4d40e5ca7207233475ca689#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn.png' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673655584 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-v5SrbNCPpD6M_p3TmSrYwTjKogs-0DMJgmjMyNZPeMO', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: '1321', | ||||||
|  |             author: '3232', | ||||||
|  |             digest: '1333', | ||||||
|  |             content: '<p>444</p>', | ||||||
|  |             contentSourceUrl: 'http://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-tlQmcl3RdC-Jcgns6IQtf7zenGy3b86WLT7GzUcrb1T', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9jelJiaDAzbmdpSkJOZ2M2QWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuNDNXVVc2ZDRYeTY0Zm1weXR6dE9vQWh1TzEwbEpUVnRfVzJyaGFDNXBkZ0ZXM2JFOTNaRHNhOHRUeFdEanhMeS01X01kMUNWQ1BpRER3cjYwTl9pMnpFLUJhZXFucVVfM1pDUXlTUEl1S25nfn4%3D&chksm=1f6354bc2814ddaa56a90ad5bc3d078601c8d1589ba01827a8170587bc830ff9747b5f59c3a0#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://mmbiz.qpic.cn/mmbiz_png/btUmCVHwbJUoicwBiacjVeQbu6QxgBVrukfSJXz509boa21SpH8OVHAqXCJiaiaAaHQJNxwwsa0gHRXVr0G5EZYamw/0?wx_fmt=png' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673628969 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-vdWrisK5EZbk4Y3tzh8P0PG0eEUbnQrh0BcsEb3WNP0', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: 'tudou', | ||||||
|  |             author: 'haha', | ||||||
|  |             digest: '312', | ||||||
|  |             content: '<p>132312</p>', | ||||||
|  |             contentSourceUrl: 'http://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-pgFtUNLu1foMSAMkoOsrQrTZ8EtTMssBLfTtzP0dfjG', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9qdkJ1ZjBoUmg2Uk9TS3RlQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuNVg2aTJsaC1fMkU2eXNacUplN3VDTTZFZkhtMjhuTUZvWkxsNDBRSXExY2tiVXRHb09TaHgtREhzY3doZ0JYeC1TSTZ5eWZldXJsOWtfbV8yMi1aYkcyZ2pOY0haM0Ntb3VSWEtxUGVFRlNBfn4%3D&chksm=1f6354ba2814ddacf0184b24d310483641ef190b1faac098c285eb416c70017e2f54decfa1af#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-pgFtUNLu1foMSAMkoOsrQrTZ8EtTMssBLfTtzP0dfjG.png' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673628760 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-u9kTIm1DhWZDdXyxsxUVv2Z5DAB99IPxkIRTUUD206k', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: '12', | ||||||
|  |             author: '333', | ||||||
|  |             digest: '123', | ||||||
|  |             content: '123', | ||||||
|  |             contentSourceUrl: 'https://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-jVixJGgnBnkBPRbuVptOW0CHYuQFyiOVNtamctS8xU8', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9qVVhpSDZUaFJWTzBBWWRVQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuNWRnTDJWYmF2NER0clV1bThmQ0xUR3hqQnJkZ3BJSUNmNDJmc0lCZ1dadkVnZ3Z5bkN4YWtVUjhoaWZWYzZURUR4NnpMd0Y4Z3U5aUdib0lkMzI4Rjg3SG9JX2FycTMxbUctOHplaTlQVVhnfn4%3D&chksm=1f6354b62814dda076c778af33f06580165d8aa81f7798d55cfabb1886b5c74d9b2124a3535c#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-jVixJGgnBnkBPRbuVptOW0CHYuQFyiOVNtamctS8xU8.jpg' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673626494 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       mediaId: 'r6ryvl6LrxBU0miaST4Y-sO24upobaENDmeByfBTfaozB3aOqSMAV0lGy-UkHXE7', | ||||||
|  |       content: { | ||||||
|  |         newsItem: [ | ||||||
|  |           { | ||||||
|  |             title: '我是标题', | ||||||
|  |             author: '我是作者', | ||||||
|  |             digest: '我是摘要', | ||||||
|  |             content: '我是内容', | ||||||
|  |             contentSourceUrl: 'https://www.iocoder.cn', | ||||||
|  |             thumbMediaId: 'r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn', | ||||||
|  |             showCoverPic: 0, | ||||||
|  |             needOpenComment: 0, | ||||||
|  |             onlyFansCanComment: 0, | ||||||
|  |             url: 'http://mp.weixin.qq.com/s?__biz=MzA3NjM4MzQzOQ==&tempkey=MTIxMl9LT2dqRnpMNUpsR0hjYWtBQWwxQ3R5R0JGTXBDM1Q0N2ZFQm8zeUphOFlwNEpXSWxTYm9RQnJ6cHVuNGNmazZTdlE5WkxvU0tfX2V5cjV2WjJiR0xjQUhyREFSZWo2eWNrUW9EYVh6ZkpWRXBLR3FmTEV6YldBMno3Q2ZvVXBSdzlaVDc3aFhndEpQWUwzWmFMUWt0YVVURE1VZ1FsQTdPMlRtc3JBfn4%3D&chksm=1f6354aa2814ddbcc2637382f963a8742993ac38ebcebe6e3411df5ac82ac7bbdb391be6494a#rd', | ||||||
|  |             thumbUrl: | ||||||
|  |               'http://test.yudao.iocoder.cn/r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn.png' | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       updateTime: 1673534279 | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   total: 6 | ||||||
|  | } | ||||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 34 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 12 KiB | 
|  | @ -1,3 +1,793 @@ | ||||||
| <template> | <template> | ||||||
|   <span>开发中</span> |   <div class="app-container"> | ||||||
|  |     <doc-alert title="公众号菜单" url="https://doc.iocoder.cn/mp/menu/" /> | ||||||
|  | 
 | ||||||
|  |     <!-- 搜索工作栏 --> | ||||||
|  |     <el-form ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> | ||||||
|  |       <el-form-item label="公众号" prop="accountId"> | ||||||
|  |         <el-select v-model="accountId" placeholder="请选择公众号"> | ||||||
|  |           <el-option | ||||||
|  |             v-for="item in accountList" | ||||||
|  |             :key="parseInt(item.id)" | ||||||
|  |             :label="item.name" | ||||||
|  |             :value="parseInt(item.id)" | ||||||
|  |           /> | ||||||
|  |         </el-select> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item> | ||||||
|  |         <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> | ||||||
|  |         <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  | 
 | ||||||
|  |     <div class="public-account-management clearfix" v-loading="loading"> | ||||||
|  |       <!--左边配置菜单--> | ||||||
|  |       <div class="left"> | ||||||
|  |         <div class="weixin-hd"> | ||||||
|  |           <div class="weixin-title">{{ name }}</div> | ||||||
|  |         </div> | ||||||
|  |         <div class="weixin-menu menu_main clearfix"> | ||||||
|  |           <div class="menu_bottom" v-for="(item, i) of menuList" :key="i"> | ||||||
|  |             <!-- 一级菜单 --> | ||||||
|  |             <div @click="menuClick(i, item)" class="menu_item" :class="{ active: isActive === i }" | ||||||
|  |               ><Icon icon="ep:fold" color="black" />{{ item.name }} | ||||||
|  |             </div> | ||||||
|  |             <!-- 以下为二级菜单--> | ||||||
|  |             <div class="submenu" v-if="isSubMenuFlag === i"> | ||||||
|  |               <div class="subtitle menu_bottom" v-for="(subItem, k) in item.children" :key="k"> | ||||||
|  |                 <div | ||||||
|  |                   class="menu_subItem" | ||||||
|  |                   v-if="item.children" | ||||||
|  |                   :class="{ active: isSubMenuActive === i + '' + k }" | ||||||
|  |                   @click="subMenuClick(subItem, i, k)" | ||||||
|  |                 > | ||||||
|  |                   {{ subItem.name }} | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |               <!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号  --> | ||||||
|  |               <div | ||||||
|  |                 class="menu_bottom menu_addicon" | ||||||
|  |                 v-if="!item.children || item.children.length < 5" | ||||||
|  |                 @click="addSubMenu(i, item)" | ||||||
|  |               > | ||||||
|  |                 <Icon icon="ep:plus" /> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <!-- 一级菜单加号 --> | ||||||
|  |           <div class="menu_bottom menu_addicon" v-if="menuList.length < 3" @click="addMenu"> | ||||||
|  |             <Icon icon="ep:plus" /> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="save_div"> | ||||||
|  |           <el-button | ||||||
|  |             class="save_btn" | ||||||
|  |             type="success" | ||||||
|  |             size="small" | ||||||
|  |             @click="handleSave" | ||||||
|  |             v-hasPermi="['mp:menu:save']" | ||||||
|  |             >保存并发布菜单</el-button | ||||||
|  |           > | ||||||
|  |           <el-button | ||||||
|  |             class="save_btn" | ||||||
|  |             type="danger" | ||||||
|  |             size="small" | ||||||
|  |             @click="handleDelete" | ||||||
|  |             v-hasPermi="['mp:menu:delete']" | ||||||
|  |             >清空菜单</el-button | ||||||
|  |           > | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <!--右边配置--> | ||||||
|  |       <div v-if="showRightFlag" class="right"> | ||||||
|  |         <div class="configure_page"> | ||||||
|  |           <div class="delete_btn"> | ||||||
|  |             <el-button size="small" type="danger" @click="handleDeleteMenu(tempObj)" | ||||||
|  |               >删除当前菜单<Icon icon="ep:delete" | ||||||
|  |             /></el-button> | ||||||
|  |           </div> | ||||||
|  |           <div> | ||||||
|  |             <span>菜单名称:</span> | ||||||
|  |             <el-input | ||||||
|  |               class="input_width" | ||||||
|  |               v-model="tempObj.name" | ||||||
|  |               placeholder="请输入菜单名称" | ||||||
|  |               :maxlength="nameMaxLength" | ||||||
|  |               clearable | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |           <div v-if="showConfigureContent"> | ||||||
|  |             <div class="menu_content"> | ||||||
|  |               <span>菜单标识:</span> | ||||||
|  |               <el-input | ||||||
|  |                 class="input_width" | ||||||
|  |                 v-model="tempObj.menuKey" | ||||||
|  |                 placeholder="请输入菜单 KEY" | ||||||
|  |                 clearable | ||||||
|  |               /> | ||||||
|  |             </div> | ||||||
|  |             <div class="menu_content"> | ||||||
|  |               <span>菜单内容:</span> | ||||||
|  |               <el-select v-model="tempObj.type" clearable placeholder="请选择" class="menu_option"> | ||||||
|  |                 <el-option | ||||||
|  |                   v-for="item in menuOptions" | ||||||
|  |                   :label="item.label" | ||||||
|  |                   :value="item.value" | ||||||
|  |                   :key="item.value" | ||||||
|  |                 /> | ||||||
|  |               </el-select> | ||||||
|  |             </div> | ||||||
|  |             <div class="configur_content" v-if="tempObj.type === 'view'"> | ||||||
|  |               <span>跳转链接:</span> | ||||||
|  |               <el-input | ||||||
|  |                 class="input_width" | ||||||
|  |                 v-model="tempObj.url" | ||||||
|  |                 placeholder="请输入链接" | ||||||
|  |                 clearable | ||||||
|  |               /> | ||||||
|  |             </div> | ||||||
|  |             <div class="configur_content" v-if="tempObj.type === 'miniprogram'"> | ||||||
|  |               <div class="applet"> | ||||||
|  |                 <span>小程序的 appid :</span> | ||||||
|  |                 <el-input | ||||||
|  |                   class="input_width" | ||||||
|  |                   v-model="tempObj.miniProgramAppId" | ||||||
|  |                   placeholder="请输入小程序的appid" | ||||||
|  |                   clearable | ||||||
|  |                 /> | ||||||
|  |               </div> | ||||||
|  |               <div class="applet"> | ||||||
|  |                 <span>小程序的页面路径:</span> | ||||||
|  |                 <el-input | ||||||
|  |                   class="input_width" | ||||||
|  |                   v-model="tempObj.miniProgramPagePath" | ||||||
|  |                   placeholder="请输入小程序的页面路径,如:pages/index" | ||||||
|  |                   clearable | ||||||
|  |                 /> | ||||||
|  |               </div> | ||||||
|  |               <div class="applet"> | ||||||
|  |                 <span>小程序的备用网页:</span> | ||||||
|  |                 <el-input | ||||||
|  |                   class="input_width" | ||||||
|  |                   v-model="tempObj.url" | ||||||
|  |                   placeholder="不支持小程序的老版本客户端将打开本网页" | ||||||
|  |                   clearable | ||||||
|  |                 /> | ||||||
|  |               </div> | ||||||
|  |               <p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p> | ||||||
|  |             </div> | ||||||
|  |             <div class="configur_content" v-if="tempObj.type === 'article_view_limited'"> | ||||||
|  |               <el-row> | ||||||
|  |                 <div class="select-item" v-if="tempObj && tempObj.replyArticles"> | ||||||
|  |                   <WxNews :articles="tempObj.replyArticles" /> | ||||||
|  |                   <el-row class="ope-row" justify="center" align="middle"> | ||||||
|  |                     <el-button type="danger" circle @click="deleteMaterial" | ||||||
|  |                       ><icon icon="ep:delete" | ||||||
|  |                     /></el-button> | ||||||
|  |                   </el-row> | ||||||
|  |                 </div> | ||||||
|  |                 <div v-else> | ||||||
|  |                   <el-row justify="center"> | ||||||
|  |                     <el-col :span="24" style="text-align: center"> | ||||||
|  |                       <el-button type="success" @click="openMaterial"> | ||||||
|  |                         素材库选择<Icon icon="ep:circle-check" /> | ||||||
|  |                       </el-button> | ||||||
|  |                     </el-col> | ||||||
|  |                   </el-row> | ||||||
|  |                 </div> | ||||||
|  |                 <el-dialog title="选择图文" v-model="dialogNewsVisible" width="90%"> | ||||||
|  |                   <WxMaterialSelect | ||||||
|  |                     :objData="{ type: 'news', accountId: accountId }" | ||||||
|  |                     @select-material="selectMaterial" | ||||||
|  |                   /> | ||||||
|  |                 </el-dialog> | ||||||
|  |               </el-row> | ||||||
|  |             </div> | ||||||
|  |             <div | ||||||
|  |               class="configur_content" | ||||||
|  |               v-if="tempObj.type === 'click' || tempObj.type === 'scancode_waitmsg'" | ||||||
|  |             > | ||||||
|  |               <WxReplySelect :objData="tempObj.reply" v-if="hackResetWxReplySelect" /> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <!-- 一进页面就显示的默认页面,当点击左边按钮的时候,就不显示了--> | ||||||
|  |       <div v-else class="right"> | ||||||
|  |         <p>请选择菜单配置</p> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
| </template> | </template> | ||||||
|  | 
 | ||||||
|  | <script setup> | ||||||
|  | import { ref, nextTick } from 'vue' | ||||||
|  | import WxReplySelect from '@/views/mp/components/wx-reply/main.vue' | ||||||
|  | import WxNews from '@/views/mp/components/wx-news/main.vue' | ||||||
|  | import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue' | ||||||
|  | import { deleteMenu, getMenuList, saveMenu } from '@/api/mp/menu' | ||||||
|  | import { getSimpleAccountList } from '@/api/mp/account' | ||||||
|  | import { handleTree } from '@/utils/tree' | ||||||
|  | import menuOptions from './menuOptions' | ||||||
|  | 
 | ||||||
|  | const message = useMessage() | ||||||
|  | 
 | ||||||
|  | // ======================== 列表查询 ======================== | ||||||
|  | // 遮罩层 | ||||||
|  | const loading = ref(true) | ||||||
|  | // 显示搜索条件 | ||||||
|  | const showSearch = ref(true) | ||||||
|  | // 公众号Id | ||||||
|  | const accountId = ref(undefined) | ||||||
|  | // 公众号名 | ||||||
|  | const name = ref('') | ||||||
|  | const menuList = ref({ children: [] }) | ||||||
|  | 
 | ||||||
|  | // const menuList = ref(menuListData) | ||||||
|  | // ======================== 菜单操作 ======================== | ||||||
|  | const isActive = ref(-1) // 一级菜单点中样式 | ||||||
|  | const isSubMenuActive = ref(-1) // 一级菜单点中样式 | ||||||
|  | const isSubMenuFlag = ref(-1) // 二级菜单显示标志 | ||||||
|  | 
 | ||||||
|  | // ======================== 菜单编辑 ======================== | ||||||
|  | const showRightFlag = ref(false) // 右边配置显示默认详情还是配置详情 | ||||||
|  | const nameMaxLength = ref(0) // 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符; | ||||||
|  | const showConfigureContent = ref(true) // 是否展示配置内容;如果有子菜单,就不显示配置内容 | ||||||
|  | const hackResetWxReplySelect = ref(false) // 重置 WxReplySelect 组件 | ||||||
|  | const tempObj = ref({}) // 右边临时变量,作为中间值牵引关系 | ||||||
|  | 
 | ||||||
|  | const tempSelfObj = ref({ | ||||||
|  |   // 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数 | ||||||
|  | }) | ||||||
|  | const dialogNewsVisible = ref(false) // 跳转图文时的素材选择弹窗 | ||||||
|  | 
 | ||||||
|  | // 公众号账号列表 | ||||||
|  | const accountList = ref([]) | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  |   accountList.value = await getSimpleAccountList() | ||||||
|  |   // 选中第一个 | ||||||
|  |   if (accountList.value.length > 0) { | ||||||
|  |     // @ts-ignore | ||||||
|  |     setAccountId(accountList.value[0].id) | ||||||
|  |   } | ||||||
|  |   await getList() | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // ======================== 列表查询 ======================== | ||||||
|  | /** 设置账号编号 */ | ||||||
|  | const setAccountId = (id) => { | ||||||
|  |   accountId.value = id | ||||||
|  |   name.value = accountList.value.find((item) => item.id === accountId.value)?.name | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const getList = async () => { | ||||||
|  |   loading.value = false | ||||||
|  |   getMenuList(accountId.value) | ||||||
|  |     .then((response) => { | ||||||
|  |       const menuData = convertMenuList(response) | ||||||
|  |       menuList.value = handleTree(menuData, 'id') | ||||||
|  |     }) | ||||||
|  |     .finally(() => { | ||||||
|  |       loading.value = false | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   resetForm() | ||||||
|  |   // 默认选中第一个 | ||||||
|  |   if (accountId.value) { | ||||||
|  |     setAccountId(accountId.value) | ||||||
|  |   } | ||||||
|  |   getList() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   resetForm() | ||||||
|  |   // 默认选中第一个 | ||||||
|  |   if (accountList.value.length > 0) { | ||||||
|  |     setAccountId(accountList.value[0].id) | ||||||
|  |   } | ||||||
|  |   handleQuery() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 将后端返回的 menuList,转换成前端的 menuList | ||||||
|  | const convertMenuList = (list) => { | ||||||
|  |   if (!list) return [] | ||||||
|  | 
 | ||||||
|  |   const menuList = [] | ||||||
|  |   list.forEach((item) => { | ||||||
|  |     const menu = { | ||||||
|  |       ...item | ||||||
|  |     } | ||||||
|  |     if (item.type === 'click' || item.type === 'scancode_waitmsg') { | ||||||
|  |       delete menu.replyMessageType | ||||||
|  |       delete menu.replyContent | ||||||
|  |       delete menu.replyMediaId | ||||||
|  |       delete menu.replyMediaUrl | ||||||
|  |       delete menu.replyDescription | ||||||
|  |       delete menu.replyArticles | ||||||
|  |       menu.reply = { | ||||||
|  |         type: item.replyMessageType, | ||||||
|  |         accountId: item.accountId, | ||||||
|  |         content: item.replyContent, | ||||||
|  |         mediaId: item.replyMediaId, | ||||||
|  |         url: item.replyMediaUrl, | ||||||
|  |         title: item.replyTitle, | ||||||
|  |         description: item.replyDescription, | ||||||
|  |         thumbMediaId: item.replyThumbMediaId, | ||||||
|  |         thumbMediaUrl: item.replyThumbMediaUrl, | ||||||
|  |         articles: item.replyArticles, | ||||||
|  |         musicUrl: item.replyMusicUrl, | ||||||
|  |         hqMusicUrl: item.replyHqMusicUrl | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     menuList.push(menu) | ||||||
|  |   }) | ||||||
|  |   return menuList | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 重置表单,清空表单数据 | ||||||
|  | const resetForm = () => { | ||||||
|  |   // 菜单操作 | ||||||
|  |   isActive.value = -1 | ||||||
|  |   isSubMenuActive.value = -1 | ||||||
|  |   isSubMenuFlag.value = -1 | ||||||
|  | 
 | ||||||
|  |   // 菜单编辑 | ||||||
|  |   showRightFlag.value = false | ||||||
|  |   nameMaxLength.value = 0 | ||||||
|  |   showConfigureContent.value = 0 | ||||||
|  |   hackResetWxReplySelect.value = false | ||||||
|  |   tempObj.value = {} | ||||||
|  |   tempSelfObj.value = {} | ||||||
|  |   dialogNewsVisible.value = false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 菜单操作 ======================== | ||||||
|  | // 一级菜单点击事件 | ||||||
|  | const menuClick = (i, item) => { | ||||||
|  |   // 右侧的表单相关 | ||||||
|  |   resetEditor() | ||||||
|  |   showRightFlag.value = true // 右边菜单 | ||||||
|  |   tempObj.value = item // 这个如果放在顶部,flag 会没有。因为重新赋值了。 | ||||||
|  |   tempSelfObj.value.grand = '1' // 表示一级菜单 | ||||||
|  |   tempSelfObj.value.index = i // 表示一级菜单索引 | ||||||
|  |   nameMaxLength.value = 4 | ||||||
|  |   showConfigureContent.value = !(item.children && item.children.length > 0) // 有子菜单,就不显示配置内容 | ||||||
|  | 
 | ||||||
|  |   // 左侧的选中 | ||||||
|  |   isActive.value = i // 一级菜单选中样式 | ||||||
|  |   isSubMenuFlag.value = i // 二级菜单显示标志 | ||||||
|  |   isSubMenuActive.value = -1 // 二级菜单去除选中样式 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 二级菜单点击事件 | ||||||
|  | const subMenuClick = (subItem, index, k) => { | ||||||
|  |   // 右侧的表单相关 | ||||||
|  |   resetEditor() | ||||||
|  |   showRightFlag.value = true // 右边菜单 | ||||||
|  |   console.log(subItem) | ||||||
|  |   tempObj.value = subItem // 将点击的数据放到临时变量,对象有引用作用 | ||||||
|  |   tempSelfObj.value.grand = '2' // 表示二级菜单 | ||||||
|  |   tempSelfObj.value.index = index // 表示一级菜单索引 | ||||||
|  |   tempSelfObj.value.secondIndex = k // 表示二级菜单索引 | ||||||
|  |   nameMaxLength.value = 7 | ||||||
|  |   showConfigureContent.value = true | ||||||
|  | 
 | ||||||
|  |   // 左侧的选中 | ||||||
|  |   isActive.value = -1 // 一级菜单去除样式 | ||||||
|  |   isSubMenuActive.value = index + '' + k // 二级菜单选中样式 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 添加横向一级菜单 | ||||||
|  | const addMenu = () => { | ||||||
|  |   const menuKeyLength = menuList.value.length | ||||||
|  |   const addButton = { | ||||||
|  |     name: '菜单名称', | ||||||
|  |     children: [], | ||||||
|  |     reply: { | ||||||
|  |       // 用于存储回复内容 | ||||||
|  |       type: 'text', | ||||||
|  |       accountId: accountId.value // 保证组件里,可以使用到对应的公众号 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   menuList.value[menuKeyLength] = addButton | ||||||
|  |   menuClick(menuKeyLength.value - 1, addButton) | ||||||
|  | } | ||||||
|  | // 添加横向二级菜单;item 表示要操作的父菜单 | ||||||
|  | const addSubMenu = (i, item) => { | ||||||
|  |   // 清空父菜单的属性,因为它只需要 name 属性即可 | ||||||
|  |   if (!item.children || item.children.length <= 0) { | ||||||
|  |     item.children = [] | ||||||
|  |     delete item['type'] | ||||||
|  |     delete item['menuKey'] | ||||||
|  |     delete item['miniProgramAppId'] | ||||||
|  |     delete item['miniProgramPagePath'] | ||||||
|  |     delete item['url'] | ||||||
|  |     delete item['reply'] | ||||||
|  |     delete item['articleId'] | ||||||
|  |     delete item['replyArticles'] | ||||||
|  |     // 关闭配置面板 | ||||||
|  |     showConfigureContent.value = false | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let subMenuKeyLength = item.children.length // 获取二级菜单key长度 | ||||||
|  |   let addButton = { | ||||||
|  |     name: '子菜单名称', | ||||||
|  |     reply: { | ||||||
|  |       // 用于存储回复内容 | ||||||
|  |       type: 'text', | ||||||
|  |       accountId: accountId.value // 保证组件里,可以使用到对应的公众号 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   item.children[subMenuKeyLength] = addButton | ||||||
|  |   subMenuClick(item.children[subMenuKeyLength], i, subMenuKeyLength) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 删除当前菜单 | ||||||
|  | const handleDeleteMenu = async () => { | ||||||
|  |   try { | ||||||
|  |     await message.confirm('确定要删除吗?') | ||||||
|  |     if (tempSelfObj.value.grand === '1') { | ||||||
|  |       // 一级菜单的删除方法 | ||||||
|  |       menuList.value.splice(tempSelfObj.value.index, 1) | ||||||
|  |     } else if (tempSelfObj.value.grand === '2') { | ||||||
|  |       // 二级菜单的删除方法 | ||||||
|  |       menuList.value[tempSelfObj.value.index].children.splice(tempSelfObj.value.secondIndex, 1) | ||||||
|  |     } | ||||||
|  |     // 提示 | ||||||
|  |     message.notifySuccess('删除成功') | ||||||
|  | 
 | ||||||
|  |     // 处理菜单的选中 | ||||||
|  |     tempObj.value = {} | ||||||
|  |     showRightFlag.value = false | ||||||
|  |     isActive.value = -1 | ||||||
|  |     isSubMenuActive.value = -1 | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 菜单编辑 ======================== | ||||||
|  | const handleSave = async () => { | ||||||
|  |   try { | ||||||
|  |     await message.confirm('确定要删除吗?') | ||||||
|  |     loading.value = true | ||||||
|  |     await saveMenu(accountId.value, convertMenuFormList()) | ||||||
|  |     getList() | ||||||
|  |     message.notifySuccess('发布成功') | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 表单 Editor 重置 | ||||||
|  | const resetEditor = () => { | ||||||
|  |   hackResetWxReplySelect.value = false // 销毁组件 | ||||||
|  |   nextTick(() => { | ||||||
|  |     console.log('nextTick') | ||||||
|  |     hackResetWxReplySelect.value = true // 重建组件 | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const handleDelete = async () => { | ||||||
|  |   try { | ||||||
|  |     await message.confirm('确定要删除吗?') | ||||||
|  |     loading.value = true | ||||||
|  |     await deleteMenu(accountId.value) | ||||||
|  |     handleQuery() | ||||||
|  |     message.notifySuccess('清空成功') | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 将前端的 menuList,转换成后端接收的 menuList | ||||||
|  | const convertMenuFormList = () => { | ||||||
|  |   const result = [] | ||||||
|  |   menuList.value.forEach((item) => { | ||||||
|  |     let menu = convertMenuForm(item) | ||||||
|  |     result.push(menu) | ||||||
|  | 
 | ||||||
|  |     // 处理子菜单 | ||||||
|  |     if (!item.children || item.children.length <= 0) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     menu.children = [] | ||||||
|  |     item.children.forEach((subItem) => { | ||||||
|  |       menu.children.push(convertMenuForm(subItem)) | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  |   return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 将前端的 menu,转换成后端接收的 menu | ||||||
|  | const convertMenuForm = (menu) => { | ||||||
|  |   let result = { | ||||||
|  |     ...menu, | ||||||
|  |     children: undefined, // 不处理子节点 | ||||||
|  |     reply: undefined // 稍后复制 | ||||||
|  |   } | ||||||
|  |   if (menu.type === 'click' || menu.type === 'scancode_waitmsg') { | ||||||
|  |     result.replyMessageType = menu.reply.type | ||||||
|  |     result.replyContent = menu.reply.content | ||||||
|  |     result.replyMediaId = menu.reply.mediaId | ||||||
|  |     result.replyMediaUrl = menu.reply.url | ||||||
|  |     result.replyTitle = menu.reply.title | ||||||
|  |     result.replyDescription = menu.reply.description | ||||||
|  |     result.replyThumbMediaId = menu.reply.thumbMediaId | ||||||
|  |     result.replyThumbMediaUrl = menu.reply.thumbMediaUrl | ||||||
|  |     result.replyArticles = menu.reply.articles | ||||||
|  |     result.replyMusicUrl = menu.reply.musicUrl | ||||||
|  |     result.replyHqMusicUrl = menu.reply.hqMusicUrl | ||||||
|  |   } | ||||||
|  |   return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ======================== 菜单编辑(素材选择) ======================== | ||||||
|  | const openMaterial = () => { | ||||||
|  |   dialogNewsVisible.value = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const selectMaterial = (item) => { | ||||||
|  |   const articleId = item.articleId | ||||||
|  |   const articles = item.content.newsItem | ||||||
|  |   // 提示,针对多图文 | ||||||
|  |   if (articles.length > 1) { | ||||||
|  |     message.alertWarning('您选择的是多图文,将默认跳转第一篇') | ||||||
|  |   } | ||||||
|  |   dialogNewsVisible.value = false | ||||||
|  | 
 | ||||||
|  |   // 设置菜单的回复 | ||||||
|  |   tempObj.value.articleId = articleId | ||||||
|  |   tempObj.value.replyArticles = [] | ||||||
|  |   articles.forEach((article) => { | ||||||
|  |     tempObj.value.replyArticles.push({ | ||||||
|  |       title: article.title, | ||||||
|  |       description: article.digest, | ||||||
|  |       picUrl: article.picUrl, | ||||||
|  |       url: article.url | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const deleteMaterial = () => { | ||||||
|  |   delete tempObj.value['articleId'] | ||||||
|  |   delete tempObj.value['replyArticles'] | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <!--本组件样式--> | ||||||
|  | <style lang="scss" scoped="scoped"> | ||||||
|  | /* 公共颜色变量 */ | ||||||
|  | .clearfix { | ||||||
|  |   *zoom: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .clearfix::after { | ||||||
|  |   content: ''; | ||||||
|  |   display: table; | ||||||
|  |   clear: both; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div { | ||||||
|  |   text-align: left; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .weixin-hd { | ||||||
|  |   color: #fff; | ||||||
|  |   text-align: center; | ||||||
|  |   position: relative; | ||||||
|  |   bottom: 426px; | ||||||
|  |   left: 0px; | ||||||
|  |   width: 300px; | ||||||
|  |   height: 64px; | ||||||
|  |   background: transparent url('./assets/menu_head.png') no-repeat 0 0; | ||||||
|  |   background-position: 0 0; | ||||||
|  |   background-size: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .weixin-title { | ||||||
|  |   color: #fff; | ||||||
|  |   font-size: 14px; | ||||||
|  |   width: 100%; | ||||||
|  |   text-align: center; | ||||||
|  |   position: absolute; | ||||||
|  |   top: 33px; | ||||||
|  |   left: 0px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .weixin-menu { | ||||||
|  |   background: transparent url('./assets/menu_foot.png') no-repeat 0 0; | ||||||
|  |   padding-left: 43px; | ||||||
|  |   font-size: 12px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .menu_option { | ||||||
|  |   width: 40% !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .public-account-management { | ||||||
|  |   min-width: 1200px; | ||||||
|  |   width: 1200px; | ||||||
|  |   margin: 0 auto; | ||||||
|  | 
 | ||||||
|  |   .left { | ||||||
|  |     float: left; | ||||||
|  |     display: inline-block; | ||||||
|  |     width: 350px; | ||||||
|  |     height: 715px; | ||||||
|  |     background: url('./assets/iphone_backImg.png') no-repeat; | ||||||
|  |     background-size: 100% auto; | ||||||
|  |     padding: 518px 25px 88px; | ||||||
|  |     position: relative; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | 
 | ||||||
|  |     /*第一级菜单*/ | ||||||
|  |     .menu_main { | ||||||
|  |       .menu_bottom { | ||||||
|  |         position: relative; | ||||||
|  |         float: left; | ||||||
|  |         display: inline-block; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         width: 85.5px; | ||||||
|  |         text-align: center; | ||||||
|  |         border: 1px solid #ebedee; | ||||||
|  |         background-color: #fff; | ||||||
|  |         cursor: pointer; | ||||||
|  | 
 | ||||||
|  |         &.menu_addicon { | ||||||
|  |           height: 46px; | ||||||
|  |           line-height: 46px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .menu_item { | ||||||
|  |           height: 44px; | ||||||
|  |           line-height: 44px; | ||||||
|  |           // text-align: center; | ||||||
|  |           box-sizing: border-box; | ||||||
|  |           width: 100%; | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: center; | ||||||
|  | 
 | ||||||
|  |           &.active { | ||||||
|  |             border: 1px solid #2bb673; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .menu_subItem { | ||||||
|  |           height: 44px; | ||||||
|  |           line-height: 44px; | ||||||
|  |           text-align: center; | ||||||
|  |           box-sizing: border-box; | ||||||
|  | 
 | ||||||
|  |           &.active { | ||||||
|  |             border: 1px solid #2bb673; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       i { | ||||||
|  |         color: #2bb673; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       /*第二级菜单*/ | ||||||
|  |       .submenu { | ||||||
|  |         position: absolute; | ||||||
|  |         width: 85.5px; | ||||||
|  |         bottom: 45px; | ||||||
|  | 
 | ||||||
|  |         .subtitle { | ||||||
|  |           background-color: #fff; | ||||||
|  |           box-sizing: border-box; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .save_div { | ||||||
|  |       margin-top: 15px; | ||||||
|  |       text-align: center; | ||||||
|  | 
 | ||||||
|  |       .save_btn { | ||||||
|  |         bottom: 20px; | ||||||
|  |         left: 100px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /*右边菜单内容*/ | ||||||
|  |   .right { | ||||||
|  |     float: left; | ||||||
|  |     width: 63%; | ||||||
|  |     background-color: #e8e7e7; | ||||||
|  |     padding: 20px; | ||||||
|  |     margin-left: 20px; | ||||||
|  |     -webkit-box-sizing: border-box; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | 
 | ||||||
|  |     .configure_page { | ||||||
|  |       .delete_btn { | ||||||
|  |         text-align: right; | ||||||
|  |         margin-bottom: 15px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .menu_content { | ||||||
|  |         margin-top: 20px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .configur_content { | ||||||
|  |         margin-top: 20px; | ||||||
|  |         background-color: #fff; | ||||||
|  |         padding: 20px 10px; | ||||||
|  |         border-radius: 5px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .blue { | ||||||
|  |         color: #29b6f6; | ||||||
|  |         margin-top: 10px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .applet { | ||||||
|  |         margin-bottom: 20px; | ||||||
|  | 
 | ||||||
|  |         span { | ||||||
|  |           width: 20%; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .input_width { | ||||||
|  |         width: 40%; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .material { | ||||||
|  |         .input_width { | ||||||
|  |           width: 30%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .el-textarea { | ||||||
|  |           width: 80%; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .el-input { | ||||||
|  |     width: 70%; | ||||||
|  |     margin-right: 2%; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | <!--素材样式--> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .pagination { | ||||||
|  |   text-align: right; | ||||||
|  |   margin-right: 25px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .select-item { | ||||||
|  |   width: 280px; | ||||||
|  |   padding: 10px; | ||||||
|  |   margin: 0 auto 10px auto; | ||||||
|  |   border: 1px solid #eaeaea; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .select-item2 { | ||||||
|  |   padding: 10px; | ||||||
|  |   margin: 0 auto 10px auto; | ||||||
|  |   border: 1px solid #eaeaea; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ope-row { | ||||||
|  |   padding-top: 10px; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .item-name { | ||||||
|  |   font-size: 12px; | ||||||
|  |   overflow: hidden; | ||||||
|  |   text-overflow: ellipsis; | ||||||
|  |   white-space: nowrap; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | export default [ | ||||||
|  |   { | ||||||
|  |     value: 'view', | ||||||
|  |     label: '跳转网页' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'miniprogram', | ||||||
|  |     label: '跳转小程序' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'click', | ||||||
|  |     label: '点击回复' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'article_view_limited', | ||||||
|  |     label: '跳转图文消息' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'scancode_push', | ||||||
|  |     label: '扫码直接返回结果' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'scancode_waitmsg', | ||||||
|  |     label: '扫码回复' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'pic_sysphoto', | ||||||
|  |     label: '系统拍照发图' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'pic_photo_or_album', | ||||||
|  |     label: '拍照或者相册' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'pic_weixin', | ||||||
|  |     label: '微信相册' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     value: 'location_select', | ||||||
|  |     label: '选择地理位置' | ||||||
|  |   } | ||||||
|  | ] | ||||||
		Loading…
	
		Reference in New Issue
	
	 dhb52
						dhb52