From 813e7d2776dc2f9bde7baa06ecac83cab8d2ff53 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 14:49:19 +0800 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8Editor?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=9B=BF=E6=8D=A2WxEditor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Editor/src/Editor.vue | 3 +- .../mp/components/wx-editor/WxEditor.vue | 104 ---- .../mp/components/wx-editor/quill-options.js | 45 -- src/views/mp/draft/editor-config.ts | 72 +++ src/views/mp/draft/index.vue | 458 +++++++++--------- 5 files changed, 307 insertions(+), 375 deletions(-) delete mode 100644 src/views/mp/components/wx-editor/WxEditor.vue delete mode 100644 src/views/mp/components/wx-editor/quill-options.js create mode 100644 src/views/mp/draft/editor-config.ts diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue index 4d8e7dde..2d723922 100644 --- a/src/components/Editor/src/Editor.vue +++ b/src/components/Editor/src/Editor.vue @@ -20,7 +20,7 @@ const props = defineProps({ editorId: propTypes.string.def('wangeEditor-1'), height: propTypes.oneOfType([Number, String]).def('500px'), editorConfig: { - type: Object as PropType<IEditorConfig>, + type: Object as PropType<Partial<IEditorConfig>>, default: () => undefined }, readonly: propTypes.bool.def(false), @@ -147,6 +147,7 @@ const editorConfig = computed((): IEditorConfig => { props.editorConfig || {} ) }) + const editorStyle = computed(() => { return { height: isNumber(props.height) ? `${props.height}px` : props.height diff --git a/src/views/mp/components/wx-editor/WxEditor.vue b/src/views/mp/components/wx-editor/WxEditor.vue deleted file mode 100644 index d2220e10..00000000 --- a/src/views/mp/components/wx-editor/WxEditor.vue +++ /dev/null @@ -1,104 +0,0 @@ -<script setup> -import { ref, reactive } from 'vue' -import { getAccessToken } from '@/utils/auth' -import { Editor } from '@/components/Editor' - -const BASE_URL = import.meta.env.VITE_BASE_URL -const actionUrl = BASE_URL + '/admin-api/mp/material/upload-news-image' // 这里写你要上传的图片服务器地址 -const headers = { Authorization: 'Bearer ' + getAccessToken() } // 设置上传的请求头部 - -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 uploadData = reactive({ - type: 'image', // TODO 芋艿:试试要不要换成 thumb - accountId: props.accountId -}) - -const onEditorChange = (text) => { - //内容改变事件 - emit('input', text) -} - -// 富文本图片上传前 -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" - /> - <Editor - editor-id="wxEditor" - ref="quillEditorRef" - :modelValue="content" - @change="(editor) => onEditorChange(editor.getText())" - /> - </div> - </div> -</template> diff --git a/src/views/mp/components/wx-editor/quill-options.js b/src/views/mp/components/wx-editor/quill-options.js deleted file mode 100644 index 5ec211ae..00000000 --- a/src/views/mp/components/wx-editor/quill-options.js +++ /dev/null @@ -1,45 +0,0 @@ -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) - } - } - } - } - } -} diff --git a/src/views/mp/draft/editor-config.ts b/src/views/mp/draft/editor-config.ts new file mode 100644 index 00000000..26c723c9 --- /dev/null +++ b/src/views/mp/draft/editor-config.ts @@ -0,0 +1,72 @@ +import { IEditorConfig } from '@wangeditor/editor' +import { getAccessToken, getTenantId } from '@/utils/auth' + +const message = useMessage() + +type InsertFnType = (url: string, alt: string, href: string) => void + +export const createEditorConfig = ( + server: string, + accountId: number | undefined +): Partial<IEditorConfig> => { + return { + MENU_CONF: { + ['uploadImage']: { + server, + // 单个文件的最大体积限制,默认为 2M + maxFileSize: 5 * 1024 * 1024, + // 最多可上传几个文件,默认为 100 + maxNumberOfFiles: 10, + // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 [] + allowedFileTypes: ['image/*'], + + // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。 + meta: { accountId: accountId }, + // 将 meta 拼接到 url 参数中,默认 false + metaWithUrl: true, + + // 自定义增加 http header + headers: { + Accept: '*', + Authorization: 'Bearer ' + getAccessToken(), + 'tenant-id': getTenantId() + }, + + // 跨域是否传递 cookie ,默认为 false + withCredentials: true, + + // 超时时间,默认为 10 秒 + timeout: 5 * 1000, // 5 秒 + + // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image + fieldName: 'file', + + // 上传之前触发 + onBeforeUpload(file: File) { + console.log(file) + return file + }, + // 上传进度的回调函数 + onProgress(progress: number) { + // progress 是 0-100 的数字 + console.log('progress', progress) + }, + onSuccess(file: File, res: any) { + console.log('onSuccess', file, res) + }, + onFailed(file: File, res: any) { + message.alertError(res.message) + console.log('onFailed', file, res) + }, + onError(file: File, err: any, res: any) { + message.alertError(err.message) + console.error('onError', file, err, res) + }, + // 自定义插入图片 + customInsert(res: any, insertFn: InsertFnType) { + insertFn(res.data, 'image', res.data) + } + } + } + } +} diff --git a/src/views/mp/draft/index.vue b/src/views/mp/draft/index.vue index d9a44076..0cc70507 100644 --- a/src/views/mp/draft/index.vue +++ b/src/views/mp/draft/index.vue @@ -71,168 +71,182 @@ <el-dialog :title="operateMaterial === 'add' ? '新建图文' : '修改图文'" width="80%" - top="20px" v-model="dialogNewsVisible" :before-close="dialogNewsClose" - :close-on-click-modal="false" + destroy-on-close > - <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%" - /> + <el-container> + <el-aside width="40%"> + <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="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 + 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" + width="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> - </div> - <el-row justify="center" class="ope-row"> - <el-button - type="primary" - circle - @click="plusNews" - 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="uploadUrl" - :headers="headers" - multiple - :limit="1" - :file-list="fileList" - :data="uploadData" - :before-upload="beforeThumbImageUpload" - :on-success="handleUploadSuccess" + <el-row justify="center" class="ope-row"> + <el-button + type="primary" + circle + @click="plusNews" + v-if="articlesAdd.length < 8 && operateMaterial === 'add'" > - <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> - <el-dialog title="选择图片" v-model="dialogImageVisible" width="80%" append-to-body> - <WxMaterialSelect - ref="materialSelectRef" - :objData="{ type: 'image', accountId: queryParams.accountId }" - @select-material="selectMaterial" - /> - </el-dialog> + <Icon icon="ep:plus" /> + </el-button> + </el-row> </div> - <el-input - :rows="8" - type="textarea" - v-model="articlesAdd[isActiveAddNews].digest" - placeholder="请输入摘要" - class="digest" - maxlength="120" - style="float: right" - /> - </div> - <!--富文本编辑器组件--> - <el-row> - <WxEditor - v-model="articlesAdd[isActiveAddNews].content" - :account-id="uploadData.accountId" - v-if="hackResetEditor" - /> - </el-row> - </div> + </el-aside> + <el-main> + <div class="" v-loading="addMaterialLoading" v-if="articlesAdd.length > 0"> + <!-- 标题、作者、原文地址 --> + <el-row :gutter="20"> + <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" + /> + </el-row> + <!-- 封面和摘要 --> + <el-row :gutter="20"> + <el-col :span="12"> + <p>封面:</p> + <div class="thumb-div"> + <el-image + v-if="articlesAdd[isActiveAddNews].thumbUrl" + style="width: 300px; max-height: 300px" + :src="articlesAdd[isActiveAddNews].thumbUrl" + fit="contain" + /> + <Icon + v-else + icon="ep:plus" + class="avatar-uploader-icon" + :class="isActiveAddNews === 0 ? 'avatar' : 'avatar1'" + /> + <div class="thumb-but"> + <el-upload + :action="uploadUrl" + :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> + <el-dialog + title="选择图片" + v-model="dialogImageVisible" + width="80%" + append-to-body + > + <WxMaterialSelect + ref="materialSelectRef" + :objData="{ type: 'image', accountId: queryParams.accountId }" + @select-material="selectMaterial" + /> + </el-dialog> + </div> + </el-col> + <el-col :span="12"> + <p>摘要:</p> + <el-input + :rows="8" + type="textarea" + v-model="articlesAdd[isActiveAddNews].digest" + placeholder="请输入摘要" + class="digest" + maxlength="120" + /> + </el-col> + </el-row> + <!--富文本编辑器组件--> + <el-row> + <Editor + v-model="articlesAdd[isActiveAddNews].content" + :editor-config="editorConfig" + /> + </el-row> + </div> + </el-main> + </el-container> <template #footer> <el-button @click="dialogNewsVisible = false">取 消</el-button> <el-button type="primary" @click="submitForm">提 交</el-button> @@ -242,7 +256,7 @@ </template> <script setup lang="ts" name="MpDraft"> -import WxEditor from '@/views/mp/components/wx-editor/WxEditor.vue' +import { Editor } from '@/components/Editor' import WxNews from '@/views/mp/components/wx-news/main.vue' import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue' import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' @@ -250,8 +264,11 @@ import { getAccessToken } from '@/utils/auth' import * as MpDraftApi from '@/api/mp/draft' import * as MpFreePublishApi from '@/api/mp/freePublish' import type { UploadFiles, UploadProps, UploadRawFile } from 'element-plus' +import { createEditorConfig } from './editor-config' // 可以用改本地数据模拟,避免API调用超限 -// import drafts from './mock' +import drafts from './mock' +import { IEditorConfig } from '@wangeditor/editor' + const message = useMessage() // 消息 const loading = ref(true) // 列表的加载中 @@ -285,14 +302,25 @@ const uploadData: UploadData = reactive({ }) // ========== 草稿新建 or 修改 ========== +interface Article { + title: string + thumbMediaId: string + author: string + digest: string + showCoverPic: string + content: string + contentSourceUrl: string + needOpenComment: string + onlyFansCanComment: string + thumbUrl: string +} const dialogNewsVisible = ref(false) const addMaterialLoading = ref(false) // 添加草稿的 loading 标识 -const articlesAdd = ref<any[]>([]) +const articlesAdd = ref<Article[]>([]) const isActiveAddNews = ref(0) const dialogImageVisible = ref(false) const operateMaterial = ref<'add' | 'edit'>('add') const articlesMediaId = ref('') -const hackResetEditor = ref(false) /** 侦听公众号变化 **/ const onAccountChanged = (id?: number) => { @@ -305,13 +333,16 @@ const onAccountChanged = (id?: number) => { const setAccountId = (id?: number) => { queryParams.accountId = id uploadData.accountId = id + editorConfig.value = createEditorConfig(uploadUrl, queryParams.accountId) } +const editorConfig = ref<Partial<IEditorConfig>>({}) + /** 查询列表 */ const getList = async () => { loading.value = true try { - const drafts = await MpDraftApi.getDraftPage(queryParams) + // const drafts = await MpDraftApi.getDraftPage(queryParams) drafts.list.forEach((item) => { const newsItem = item.content.newsItem // 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面 @@ -329,7 +360,6 @@ const getList = async () => { // ======================== 新增/修改草稿 ======================== /** 新增按钮操作 */ const handleAdd = () => { - resetEditor() reset() // 打开表单,并设置初始化 operateMaterial.value = 'add' @@ -338,7 +368,6 @@ const handleAdd = () => { /** 更新按钮操作 */ const handleUpdate = (item: any) => { - resetEditor() reset() articlesMediaId.value = item.mediaId articlesAdd.value = JSON.parse(JSON.stringify(item.content.newsItem)) @@ -370,7 +399,6 @@ const dialogNewsClose = async (onDone: () => {}) => { try { await message.confirm('修改内容可能还未保存,确定关闭吗?') reset() - resetEditor() onDone() } catch {} } @@ -381,14 +409,6 @@ const reset = () => { articlesAdd.value = [buildEmptyArticle()] } -// 表单 Editor 重置 -const resetEditor = () => { - hackResetEditor.value = false // 销毁组件 - nextTick(() => { - hackResetEditor.value = true // 重建组件 - }) -} - // 将图文向下移动 const downNews = (index: number) => { let temp = articlesAdd.value[index] @@ -398,8 +418,8 @@ const downNews = (index: number) => { } // 将图文向上移动 -const upNews = (index) => { - let temp = articlesAdd.value[index] +const upNews = (index: number) => { + const temp = articlesAdd.value[index] articlesAdd.value[index] = articlesAdd.value[index - 1] articlesAdd.value[index - 1] = temp isActiveAddNews.value = index - 1 @@ -407,7 +427,6 @@ const upNews = (index) => { // 选中指定 index 的图文 const activeNews = (index: number) => { - resetEditor() isActiveAddNews.value = index } @@ -429,7 +448,7 @@ const plusNews = () => { } // 创建空的 article -const buildEmptyArticle = () => { +const buildEmptyArticle = (): Article => { return { title: '', thumbMediaId: '', @@ -455,8 +474,8 @@ const beforeThumbImageUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawF addMaterialLoading.value = false return false } - const isLt = rawFile.size / 1024 / 1024 < 2 - if (!isLt) { + + if (rawFile.size / 1024 / 1024 > 2) { message.error('上传图片大小不能超过 2M!') addMaterialLoading.value = false return false @@ -465,10 +484,10 @@ const beforeThumbImageUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawF return true } -const handleUploadSuccess: UploadProps['onSuccess'] = (response: any) => { +const handleUploadSuccess: UploadProps['onSuccess'] = (res: any) => { addMaterialLoading.value = false - if (response.code !== 0) { - message.error('上传出错:' + response.msg) + if (res.code !== 0) { + message.error('上传出错:' + res.msg) return false } @@ -476,8 +495,8 @@ const handleUploadSuccess: UploadProps['onSuccess'] = (response: any) => { fileList.value = [] // 设置草稿的封面字段 - articlesAdd.value[isActiveAddNews.value].thumbMediaId = response.data.mediaId - articlesAdd.value[isActiveAddNews.value].thumbUrl = response.data.url + articlesAdd.value[isActiveAddNews.value].thumbMediaId = res.data.mediaId + articlesAdd.value[isActiveAddNews.value].thumbUrl = res.data.url } // 选择 or 上传完素材,设置回草稿 @@ -502,7 +521,7 @@ const handlePublish = async (item: any) => { await message.confirm(content) await MpFreePublishApi.submitFreePublish(accountId, mediaId) message.notifySuccess('发布成功') - getList() + await getList() } catch {} } @@ -514,7 +533,7 @@ const handleDelete = async (item: any) => { await message.confirm('此操作将永久删除该草稿, 是否继续?') await MpDraftApi.deleteDraft(accountId, mediaId) message.notifySuccess('删除成功') - getList() + await getList() } catch {} } </script> @@ -535,6 +554,13 @@ const handleDelete = async (item: any) => { padding-top: 5px; } +.el-row { + margin-bottom: 20px; +} +.el-row:last-child { + margin-bottom: 0; +} + .item-name { font-size: 12px; overflow: hidden; @@ -548,35 +574,33 @@ const handleDelete = async (item: any) => { } /*新增图文*/ -.left { - display: inline-block; - width: 35%; - vertical-align: top; - margin-top: 200px; -} +// .left { +// display: inline-block; +// vertical-align: top; +// margin-top: 200px; +// } -.right { - display: inline-block; - width: 60%; - margin-top: -40px; -} +// .right { +// display: inline-block; +// width: 100%; +// } -.avatar-uploader { - width: 20%; - display: inline-block; -} +// .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 { +// border-radius: 6px; +// cursor: pointer; +// position: relative; +// overflow: hidden; +// text-align: unset !important; +// } -.avatar-uploader .el-upload:hover { - border-color: #165dff; -} +// .avatar-uploader .el-upload:hover { +// border-color: #165dff; +// } .avatar-uploader-icon { border: 1px solid #d9d9d9; @@ -599,7 +623,7 @@ const handleDelete = async (item: any) => { } .digest { - width: 60%; + width: 100%; display: inline-block; vertical-align: top; } @@ -620,28 +644,16 @@ const handleDelete = async (item: any) => { 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) { @@ -707,10 +719,6 @@ p { background-color: #acadae; } -.input-tt { - padding: 5px; -} - .activeAddNews { border: 5px solid #2bb673; } @@ -747,7 +755,7 @@ p { .thumb-div { display: inline-block; - width: 30%; + width: 100%; text-align: center; } From 92da7e341b3f80ed78dbec903aebd13a965ac4d3 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:08:58 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8ElDialog:destroy-o?= =?UTF-8?q?n-close=E5=B1=9E=E6=80=A7=E8=A7=A3=E5=86=B3=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E6=A1=86=E9=87=8D=E6=96=B0=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/mp/autoReply/index.vue | 21 ++++----------------- src/views/mp/message/index.vue | 6 +++--- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/views/mp/autoReply/index.vue b/src/views/mp/autoReply/index.vue index 4c8eb388..77bcf6f7 100644 --- a/src/views/mp/autoReply/index.vue +++ b/src/views/mp/autoReply/index.vue @@ -140,7 +140,7 @@ </el-table> <!-- 添加或修改自动回复的对话框 --> - <el-dialog :title="title" v-model="showReplyFormDialog" width="800px" append-to-body> + <el-dialog :title="title" v-model="showReplyFormDialog" width="800px" destroy-on-close> <el-form ref="formRef" :model="replyForm" :rules="rules" label-width="80px"> <el-form-item label="消息类型" prop="requestMessageType" v-if="msgType === MsgType.Message"> <el-select v-model="replyForm.requestMessageType" placeholder="请选择"> @@ -167,7 +167,7 @@ <el-input v-model="replyForm.requestKeyword" placeholder="请输入内容" clearable /> </el-form-item> <el-form-item label="回复消息"> - <WxReplySelect :objData="objData" v-if="hackResetWxReplySelect" /> + <WxReplySelect :objData="objData" /> </el-form-item> </el-form> <template #footer> @@ -195,7 +195,7 @@ const message = useMessage() const formRef = ref() // 消息类型(Follow: 关注时回复;Message: 消息回复;Keyword: 关键词回复) -// 作为tab.name +// 作为tab.name,enum的数字不能随意修改,与api参数相关 enum MsgType { Follow = 1, Message = 2, @@ -277,9 +277,6 @@ const rules = { requestMatch: [{ required: true, message: '请求的关键字的匹配不能为空', trigger: 'blur' }] } -// 重置 WxReplySelect 组件,解决无法清除的问题 -const hackResetWxReplySelect = ref(false) - const onAccountChanged = (id?: number) => { queryParams.accountId = id getList() @@ -314,7 +311,6 @@ const handleTabChange = (tabName: TabPaneName) => { /** 新增按钮操作 */ const handleAdd = () => { reset() - resetEditor() // 打开表单,并设置初始化 objData.value = { type: 'text', @@ -328,7 +324,6 @@ const handleAdd = () => { /** 修改按钮操作 */ const handleUpdate = async (row: any) => { reset() - resetEditor() const data = await MpAutoReplyApi.getAutoReply(row.id) // 设置属性 @@ -386,7 +381,7 @@ const handleSubmit = async () => { } showReplyFormDialog.value = false - getList() + await getList() } // 表单重置 @@ -408,14 +403,6 @@ const cancel = () => { reset() } -// 表单 Editor 重置 -const resetEditor = () => { - hackResetWxReplySelect.value = false // 销毁组件 - nextTick(() => { - hackResetWxReplySelect.value = true // 重建组件 - }) -} - const handleDelete = async (row) => { await message.confirm('是否确认删除此数据?') await MpAutoReplyApi.deleteAutoReply(row.id) diff --git a/src/views/mp/message/index.vue b/src/views/mp/message/index.vue index d13acf81..60191db8 100644 --- a/src/views/mp/message/index.vue +++ b/src/views/mp/message/index.vue @@ -190,10 +190,9 @@ v-model="showMessageBox" @click="showMessageBox = true" width="50%" + destroy-on-close > - <template #footer> - <WxMsg :user-id="userId" v-if="showMessageBox" /> - </template> + <WxMsg :user-id="userId" /> </el-dialog> </ContentWrap> </template> @@ -262,6 +261,7 @@ const handleQuery = () => { /** 重置按钮操作 */ const resetQuery = async () => { + // 暂存accountId,并在reset后恢复 const accountId = queryParams.accountId queryFormRef.value?.resetFields() queryParams.accountId = accountId From dc32b9242d0819081126a48698c966341f066bb6 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:15:01 +0800 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4WxAccountSele?= =?UTF-8?q?ct?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/mp/components/WxMpSelect.vue | 36 ---------------- .../mp/components/wx-account-select/main.vue | 42 ++++++++----------- src/views/mp/message/index.vue | 4 +- 3 files changed, 19 insertions(+), 63 deletions(-) delete mode 100644 src/views/mp/components/WxMpSelect.vue diff --git a/src/views/mp/components/WxMpSelect.vue b/src/views/mp/components/WxMpSelect.vue deleted file mode 100644 index 615745de..00000000 --- a/src/views/mp/components/WxMpSelect.vue +++ /dev/null @@ -1,36 +0,0 @@ -<template> - <el-select v-model="account.id" placeholder="请选择公众号" class="!w-240px" @change="onChanged"> - <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" /> - </el-select> -</template> -<!-- TODO @芋艿:WxMpSelect 改成 WxAccountSelect,然后挪到现有的 wx-account-select 包下 --> -<script lang="ts" setup name="WxMpSelect"> -import * as MpAccountApi from '@/api/mp/account' - -const account: MpAccountApi.AccountVO = reactive({ - id: undefined, - name: '' -}) -const accountList: Ref<MpAccountApi.AccountVO[]> = ref([]) - -const emit = defineEmits<{ - (e: 'change', id?: number, name?: string): void -}>() - -onMounted(() => { - handleQuery() -}) - -const handleQuery = async () => { - accountList.value = await MpAccountApi.getSimpleAccountList() - // 默认选中第一个 - if (accountList.value.length > 0) { - account.id = accountList.value[0].id - emit('change', account.id, account.name) - } -} - -const onChanged = () => { - emit('change', account.id, account.name) -} -</script> diff --git a/src/views/mp/components/wx-account-select/main.vue b/src/views/mp/components/wx-account-select/main.vue index 4eb99615..61963cb8 100644 --- a/src/views/mp/components/wx-account-select/main.vue +++ b/src/views/mp/components/wx-account-select/main.vue @@ -1,29 +1,21 @@ <template> - <el-form class="-mb-15px" ref="queryFormRef" :inline="true" label-width="68px"> - <el-form-item label="公众号" prop="accountId"> - <!-- TODO 芋艿:需要将 el-form 和 el-select 解耦 --> - <el-select - v-model="accountId" - placeholder="请选择公众号" - class="!w-240px" - @change="accountChanged()" - > - <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" /> - </el-select> - </el-form-item> - <el-form-item> - <slot name="actions"></slot> - </el-form-item> - </el-form> + <el-select v-model="account.id" placeholder="请选择公众号" class="!w-240px" @change="onChanged"> + <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" /> + </el-select> </template> -<script setup name="WxAccountSelect"> +<script lang="ts" setup name="WxAccountSelect"> import * as MpAccountApi from '@/api/mp/account' -const accountId = ref() -const accountList = ref([]) -const queryFormRef = ref() -const emit = defineEmits(['change']) +const account: MpAccountApi.AccountVO = reactive({ + id: undefined, + name: '' +}) +const accountList: Ref<MpAccountApi.AccountVO[]> = ref([]) + +const emit = defineEmits<{ + (e: 'change', id?: number, name?: string): void +}>() onMounted(() => { handleQuery() @@ -33,12 +25,12 @@ const handleQuery = async () => { accountList.value = await MpAccountApi.getSimpleAccountList() // 默认选中第一个 if (accountList.value.length > 0) { - accountId.value = accountList.value[0].id - emit('change', accountId.value) + account.id = accountList.value[0].id + emit('change', account.id, account.name) } } -const accountChanged = () => { - emit('change', accountId.value) +const onChanged = () => { + emit('change', account.id, account.name) } </script> diff --git a/src/views/mp/message/index.vue b/src/views/mp/message/index.vue index 60191db8..4ab19fda 100644 --- a/src/views/mp/message/index.vue +++ b/src/views/mp/message/index.vue @@ -9,7 +9,7 @@ label-width="68px" > <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> <el-form-item label="消息类型" prop="type"> <el-select v-model="queryParams.type" placeholder="请选择消息类型" class="!w-240px"> @@ -203,7 +203,7 @@ import WxMsg from '@/views/mp/components/wx-msg/main.vue' import WxLocation from '@/views/mp/components/wx-location/main.vue' import WxMusic from '@/views/mp/components/wx-music/main.vue' import WxNews from '@/views/mp/components/wx-news/main.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import * as MpMessageApi from '@/api/mp/message' import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' From 1aae769562d42b459362f43a156eb6891863c726 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:15:35 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=E5=9C=A8vscode=E4=B8=AD=E6=8A=98?= =?UTF-8?q?=E5=8F=A0=E6=96=87=E4=BB=B6=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 38cc3052..3036ebf1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,5 +40,15 @@ "i18n-ally.displayLanguage": "zh-CN", "i18n-ally.enabledFrameworks": ["vue", "react"], "god.tsconfig": "./tsconfig.json", - "vue-i18n.i18nPaths": "src/locales" + "vue-i18n.i18nPaths": "src/locales", + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.expand": false, + "explorer.fileNesting.patterns": { + "*.ts": "$(capture).test.ts, $(capture).test.tsx", + "*.tsx": "$(capture).test.ts, $(capture).test.tsx", + "*.env": "$(capture).env.*", + "CHANGELOG.md": "CHANGELOG*", + "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc,vite.config.*,windi.*,tailwind.*,tsconfig.*,postcss*", + ".eslintrc.js": ".eslintignore,.eslintrc-*,.prettierignore,.stylelintignore,.commitlintrc.js,.prettierrc.js,.stylelint*,stylelint*,prettier.*,.editorconfig" + } } From bb49c6bbda5c13e78fef8f5b9feae1132fd0520b Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:16:50 +0800 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9A=84auto-*.d.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/.gitignore | 1 + src/types/auto-components.d.ts | 128 --------------------------------- src/types/auto-imports.d.ts | 76 -------------------- 3 files changed, 1 insertion(+), 204 deletions(-) create mode 100644 src/types/.gitignore delete mode 100644 src/types/auto-components.d.ts delete mode 100644 src/types/auto-imports.d.ts diff --git a/src/types/.gitignore b/src/types/.gitignore new file mode 100644 index 00000000..a00fe5dd --- /dev/null +++ b/src/types/.gitignore @@ -0,0 +1 @@ +auto-*.d.ts diff --git a/src/types/auto-components.d.ts b/src/types/auto-components.d.ts deleted file mode 100644 index a3afbb94..00000000 --- a/src/types/auto-components.d.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -import '@vue/runtime-core' - -export {} - -declare module '@vue/runtime-core' { - export interface GlobalComponents { - Backtop: typeof import('./../components/Backtop/src/Backtop.vue')['default'] - ConfigGlobal: typeof import('./../components/ConfigGlobal/src/ConfigGlobal.vue')['default'] - ContentDetailWrap: typeof import('./../components/ContentDetailWrap/src/ContentDetailWrap.vue')['default'] - ContentWrap: typeof import('./../components/ContentWrap/src/ContentWrap.vue')['default'] - CopperModal: typeof import('./../components/Cropper/src/CopperModal.vue')['default'] - CountTo: typeof import('./../components/CountTo/src/CountTo.vue')['default'] - Crontab: typeof import('./../components/Crontab/src/Crontab.vue')['default'] - Cropper: typeof import('./../components/Cropper/src/Cropper.vue')['default'] - CropperAvatar: typeof import('./../components/Cropper/src/CropperAvatar.vue')['default'] - Descriptions: typeof import('./../components/Descriptions/src/Descriptions.vue')['default'] - Dialog: typeof import('./../components/Dialog/src/Dialog.vue')['default'] - DictTag: typeof import('./../components/DictTag/src/DictTag.vue')['default'] - DocAlert: typeof import('./../components/DocAlert/index.vue')['default'] - Echart: typeof import('./../components/Echart/src/Echart.vue')['default'] - Editor: typeof import('./../components/Editor/src/Editor.vue')['default'] - ElAlert: typeof import('element-plus/es')['ElAlert'] - ElAutoResizer: typeof import('element-plus/es')['ElAutoResizer'] - ElAvatar: typeof import('element-plus/es')['ElAvatar'] - ElBadge: typeof import('element-plus/es')['ElBadge'] - ElButton: typeof import('element-plus/es')['ElButton'] - ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] - ElCard: typeof import('element-plus/es')['ElCard'] - ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] - ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] - ElCol: typeof import('element-plus/es')['ElCol'] - ElCollapse: typeof import('element-plus/es')['ElCollapse'] - ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] - ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition'] - ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] - ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] - ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] - ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] - ElDialog: typeof import('element-plus/es')['ElDialog'] - ElDivider: typeof import('element-plus/es')['ElDivider'] - ElDrawer: typeof import('element-plus/es')['ElDrawer'] - ElDropdown: typeof import('element-plus/es')['ElDropdown'] - ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] - ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] - ElementBaseInfo: typeof import('./../components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue')['default'] - ElementForm: typeof import('./../components/bpmnProcessDesigner/package/penal/form/ElementForm.vue')['default'] - ElementListeners: typeof import('./../components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue')['default'] - ElementMultiInstance: typeof import('./../components/bpmnProcessDesigner/package/penal/multi-instance/ElementMultiInstance.vue')['default'] - ElementOtherConfig: typeof import('./../components/bpmnProcessDesigner/package/penal/other/ElementOtherConfig.vue')['default'] - ElementProperties: typeof import('./../components/bpmnProcessDesigner/package/penal/properties/ElementProperties.vue')['default'] - ElementTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/ElementTask.vue')['default'] - ElForm: typeof import('element-plus/es')['ElForm'] - ElFormItem: typeof import('element-plus/es')['ElFormItem'] - ElIcon: typeof import('element-plus/es')['ElIcon'] - ElImage: typeof import('element-plus/es')['ElImage'] - ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] - ElInput: typeof import('element-plus/es')['ElInput'] - ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] - ElLink: typeof import('element-plus/es')['ElLink'] - ElOption: typeof import('element-plus/es')['ElOption'] - ElPagination: typeof import('element-plus/es')['ElPagination'] - ElPopover: typeof import('element-plus/es')['ElPopover'] - ElRadio: typeof import('element-plus/es')['ElRadio'] - ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] - ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] - ElRow: typeof import('element-plus/es')['ElRow'] - ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] - ElSelect: typeof import('element-plus/es')['ElSelect'] - ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] - ElSpace: typeof import('element-plus/es')['ElSpace'] - ElSwitch: typeof import('element-plus/es')['ElSwitch'] - ElTable: typeof import('element-plus/es')['ElTable'] - ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] - ElTableV2: typeof import('element-plus/es')['ElTableV2'] - ElTabPane: typeof import('element-plus/es')['ElTabPane'] - ElTabs: typeof import('element-plus/es')['ElTabs'] - ElTag: typeof import('element-plus/es')['ElTag'] - ElTimeline: typeof import('element-plus/es')['ElTimeline'] - ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem'] - ElTooltip: typeof import('element-plus/es')['ElTooltip'] - ElTree: typeof import('element-plus/es')['ElTree'] - ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] - ElUpload: typeof import('element-plus/es')['ElUpload'] - Error: typeof import('./../components/Error/src/Error.vue')['default'] - FlowCondition: typeof import('./../components/bpmnProcessDesigner/package/penal/flow-condition/FlowCondition.vue')['default'] - Form: typeof import('./../components/Form/src/Form.vue')['default'] - Highlight: typeof import('./../components/Highlight/src/Highlight.vue')['default'] - Icon: typeof import('./../components/Icon/src/Icon.vue')['default'] - IconSelect: typeof import('./../components/Icon/src/IconSelect.vue')['default'] - IFrame: typeof import('./../components/IFrame/src/IFrame.vue')['default'] - ImageViewer: typeof import('./../components/ImageViewer/src/ImageViewer.vue')['default'] - Infotip: typeof import('./../components/Infotip/src/Infotip.vue')['default'] - InputPassword: typeof import('./../components/InputPassword/src/InputPassword.vue')['default'] - Pagination: typeof import('./../components/Pagination/index.vue')['default'] - ProcessDesigner: typeof import('./../components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue')['default'] - ProcessPalette: typeof import('./../components/bpmnProcessDesigner/package/palette/ProcessPalette.vue')['default'] - ProcessViewer: typeof import('./../components/bpmnProcessDesigner/package/designer/ProcessViewer.vue')['default'] - PropertiesPanel: typeof import('./../components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue')['default'] - Qrcode: typeof import('./../components/Qrcode/src/Qrcode.vue')['default'] - ReceiveTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ReceiveTask.vue')['default'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - ScriptTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ScriptTask.vue')['default'] - Search: typeof import('./../components/Search/src/Search.vue')['default'] - SignalAndMessage: typeof import('./../components/bpmnProcessDesigner/package/penal/signal-message/SignalAndMessage.vue')['default'] - Sticky: typeof import('./../components/Sticky/src/Sticky.vue')['default'] - Table: typeof import('./../components/Table/src/Table.vue')['default'] - Tooltip: typeof import('./../components/Tooltip/src/Tooltip.vue')['default'] - UploadFile: typeof import('./../components/UploadFile/src/UploadFile.vue')['default'] - UploadImg: typeof import('./../components/UploadFile/src/UploadImg.vue')['default'] - UploadImgs: typeof import('./../components/UploadFile/src/UploadImgs.vue')['default'] - UserTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/UserTask.vue')['default'] - UserTaskListeners: typeof import('./../components/bpmnProcessDesigner/package/penal/listeners/UserTaskListeners.vue')['default'] - Verify: typeof import('./../components/Verifition/src/Verify.vue')['default'] - VerifyPoints: typeof import('./../components/Verifition/src/Verify/VerifyPoints.vue')['default'] - VerifySlide: typeof import('./../components/Verifition/src/Verify/VerifySlide.vue')['default'] - XButton: typeof import('./../components/XButton/src/XButton.vue')['default'] - XTextButton: typeof import('./../components/XButton/src/XTextButton.vue')['default'] - } - export interface ComponentCustomProperties { - vLoading: typeof import('element-plus/es')['ElLoadingDirective'] - } -} diff --git a/src/types/auto-imports.d.ts b/src/types/auto-imports.d.ts deleted file mode 100644 index 75cf16d9..00000000 --- a/src/types/auto-imports.d.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// Generated by unplugin-auto-import -export {} -declare global { - const DICT_TYPE: typeof import('@/utils/dict')['DICT_TYPE'] - const EffectScope: typeof import('vue')['EffectScope'] - const computed: typeof import('vue')['computed'] - const createApp: typeof import('vue')['createApp'] - const customRef: typeof import('vue')['customRef'] - const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] - const defineComponent: typeof import('vue')['defineComponent'] - const effectScope: typeof import('vue')['effectScope'] - const getCurrentInstance: typeof import('vue')['getCurrentInstance'] - const getCurrentScope: typeof import('vue')['getCurrentScope'] - const h: typeof import('vue')['h'] - const inject: typeof import('vue')['inject'] - const isProxy: typeof import('vue')['isProxy'] - const isReactive: typeof import('vue')['isReactive'] - const isReadonly: typeof import('vue')['isReadonly'] - const isRef: typeof import('vue')['isRef'] - const markRaw: typeof import('vue')['markRaw'] - const nextTick: typeof import('vue')['nextTick'] - const onActivated: typeof import('vue')['onActivated'] - const onBeforeMount: typeof import('vue')['onBeforeMount'] - const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] - const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] - const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] - const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] - const onDeactivated: typeof import('vue')['onDeactivated'] - const onErrorCaptured: typeof import('vue')['onErrorCaptured'] - const onMounted: typeof import('vue')['onMounted'] - const onRenderTracked: typeof import('vue')['onRenderTracked'] - const onRenderTriggered: typeof import('vue')['onRenderTriggered'] - const onScopeDispose: typeof import('vue')['onScopeDispose'] - const onServerPrefetch: typeof import('vue')['onServerPrefetch'] - const onUnmounted: typeof import('vue')['onUnmounted'] - const onUpdated: typeof import('vue')['onUpdated'] - const provide: typeof import('vue')['provide'] - const reactive: typeof import('vue')['reactive'] - const readonly: typeof import('vue')['readonly'] - const ref: typeof import('vue')['ref'] - const required: typeof import('@/utils/formRules')['required'] - const resolveComponent: typeof import('vue')['resolveComponent'] - const shallowReactive: typeof import('vue')['shallowReactive'] - const shallowReadonly: typeof import('vue')['shallowReadonly'] - const shallowRef: typeof import('vue')['shallowRef'] - const toRaw: typeof import('vue')['toRaw'] - const toRef: typeof import('vue')['toRef'] - const toRefs: typeof import('vue')['toRefs'] - const triggerRef: typeof import('vue')['triggerRef'] - const unref: typeof import('vue')['unref'] - const useAttrs: typeof import('vue')['useAttrs'] - const useCrudSchemas: typeof import('@/hooks/web/useCrudSchemas')['useCrudSchemas'] - const useCssModule: typeof import('vue')['useCssModule'] - const useCssVars: typeof import('vue')['useCssVars'] - const useI18n: typeof import('@/hooks/web/useI18n')['useI18n'] - const useLink: typeof import('vue-router')['useLink'] - const useMessage: typeof import('@/hooks/web/useMessage')['useMessage'] - const useRoute: typeof import('vue-router')['useRoute'] - const useRouter: typeof import('vue-router')['useRouter'] - const useSlots: typeof import('vue')['useSlots'] - const useTable: typeof import('@/hooks/web/useTable')['useTable'] - const useVxeCrudSchemas: typeof import('@/hooks/web/useVxeCrudSchemas')['useVxeCrudSchemas'] - const useXTable: typeof import('@/hooks/web/useXTable')['useXTable'] - const watch: typeof import('vue')['watch'] - const watchEffect: typeof import('vue')['watchEffect'] - const watchPostEffect: typeof import('vue')['watchPostEffect'] - const watchSyncEffect: typeof import('vue')['watchSyncEffect'] -} -// for type re-export -declare global { - // @ts-ignore - export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue' -} From 4f3e7ecaac25db502ed06fc9f0021cb708b63a38 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:22:23 +0800 Subject: [PATCH 6/9] fix: WxMpSelect => WxAccountSelect --- src/views/mp/autoReply/index.vue | 4 ++-- src/views/mp/draft/index.vue | 4 ++-- src/views/mp/freePublish/index.vue | 4 ++-- src/views/mp/material/index.vue | 4 ++-- src/views/mp/menu/index.vue | 4 ++-- src/views/mp/tag/index.vue | 4 ++-- src/views/mp/user/index.vue | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/views/mp/autoReply/index.vue b/src/views/mp/autoReply/index.vue index 77bcf6f7..0fd6001d 100644 --- a/src/views/mp/autoReply/index.vue +++ b/src/views/mp/autoReply/index.vue @@ -5,7 +5,7 @@ <ContentWrap> <el-form class="-mb-15px" :model="queryParams" :inline="true" label-width="68px"> <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> </el-form> </ContentWrap> @@ -183,7 +183,7 @@ import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue' import WxMusic from '@/views/mp/components/wx-music/main.vue' import WxNews from '@/views/mp/components/wx-news/main.vue' import WxReplySelect from '@/views/mp/components/wx-reply/main.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import * as MpAutoReplyApi from '@/api/mp/autoReply' import { DICT_TYPE, getDictOptions } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' diff --git a/src/views/mp/draft/index.vue b/src/views/mp/draft/index.vue index 0cc70507..bd9e5b74 100644 --- a/src/views/mp/draft/index.vue +++ b/src/views/mp/draft/index.vue @@ -11,7 +11,7 @@ label-width="68px" > <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> <el-form-item> <el-button type="primary" plain @click="handleAdd" v-hasPermi="['mp:draft:create']"> @@ -259,7 +259,7 @@ import { Editor } from '@/components/Editor' import WxNews from '@/views/mp/components/wx-news/main.vue' import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import { getAccessToken } from '@/utils/auth' import * as MpDraftApi from '@/api/mp/draft' import * as MpFreePublishApi from '@/api/mp/freePublish' diff --git a/src/views/mp/freePublish/index.vue b/src/views/mp/freePublish/index.vue index 7a15b31f..0a473f1d 100644 --- a/src/views/mp/freePublish/index.vue +++ b/src/views/mp/freePublish/index.vue @@ -11,7 +11,7 @@ label-width="68px" > <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> </el-form> </ContentWrap> @@ -51,7 +51,7 @@ <script lang="ts" setup name="MpFreePublish"> import * as FreePublishApi from '@/api/mp/freePublish' import WxNews from '@/views/mp/components/wx-news/main.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 diff --git a/src/views/mp/material/index.vue b/src/views/mp/material/index.vue index 81d8fb08..c6d8055d 100644 --- a/src/views/mp/material/index.vue +++ b/src/views/mp/material/index.vue @@ -4,7 +4,7 @@ <ContentWrap> <el-form class="-mb-15px" :inline="true" label-width="68px"> <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> </el-form> </ContentWrap> @@ -248,7 +248,7 @@ <script lang="ts" setup name="MpMaterial"> import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue' import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import * as MpMaterialApi from '@/api/mp/material' import * as authUtil from '@/utils/auth' import { dateFormatter } from '@/utils/formatTime' diff --git a/src/views/mp/menu/index.vue b/src/views/mp/menu/index.vue index fea08614..3d428f06 100644 --- a/src/views/mp/menu/index.vue +++ b/src/views/mp/menu/index.vue @@ -4,7 +4,7 @@ <ContentWrap> <el-form class="-mb-15px" ref="queryFormRef" :inline="true" label-width="68px"> <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> </el-form> </ContentWrap> @@ -192,7 +192,7 @@ 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 WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import * as MpMenuApi from '@/api/mp/menu' import { handleTree } from '@/utils/tree' import menuOptions from './menuOptions' diff --git a/src/views/mp/tag/index.vue b/src/views/mp/tag/index.vue index 125c8702..6689529d 100644 --- a/src/views/mp/tag/index.vue +++ b/src/views/mp/tag/index.vue @@ -11,7 +11,7 @@ label-width="68px" > <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> <el-form-item> <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mp:tag:create']"> @@ -74,7 +74,7 @@ import { dateFormatter } from '@/utils/formatTime' import * as MpTagApi from '@/api/mp/tag' import TagForm from './TagForm.vue' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 diff --git a/src/views/mp/user/index.vue b/src/views/mp/user/index.vue index 5b2ec3bd..8a54d38e 100644 --- a/src/views/mp/user/index.vue +++ b/src/views/mp/user/index.vue @@ -11,7 +11,7 @@ label-width="68px" > <el-form-item label="公众号" prop="accountId"> - <WxMpSelect @change="onAccountChanged" /> + <WxAccountSelect @change="onAccountChanged" /> </el-form-item> <el-form-item label="用户标识" prop="openid"> <el-input @@ -97,7 +97,7 @@ import { dateFormatter } from '@/utils/formatTime' import * as MpUserApi from '@/api/mp/user' import * as MpTagApi from '@/api/mp/tag' -import WxMpSelect from '@/views/mp/components/WxMpSelect.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import type { FormInstance } from 'element-plus' import UserForm from './UserForm.vue' From 0b055b5db47d6227999b72c5245e53fed74a2f3a Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 15:26:06 +0800 Subject: [PATCH 7/9] fix: type='text' => type='primary' link --- .../package/penal/form/ElementForm.vue | 9 ++++++--- src/views/Login/components/LoginForm.vue | 3 ++- src/views/Login/components/MobileForm.vue | 3 ++- src/views/bpm/definition/index.vue | 3 ++- src/views/bpm/model/index.vue | 6 ++++-- src/views/mp/components/wx-reply/main.vue | 2 +- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/components/bpmnProcessDesigner/package/penal/form/ElementForm.vue b/src/components/bpmnProcessDesigner/package/penal/form/ElementForm.vue index cea05550..198f0f3f 100644 --- a/src/components/bpmnProcessDesigner/package/penal/form/ElementForm.vue +++ b/src/components/bpmnProcessDesigner/package/penal/form/ElementForm.vue @@ -111,7 +111,8 @@ > <el-divider direction="vertical" /> <el-button - type="text" + type="primary" + link style="color: #ff4d4f" @click="removeFieldOptionItem(scope, scope.$index, 'enum')" >移除</el-button @@ -143,7 +144,8 @@ > <el-divider direction="vertical" /> <el-button - type="text" + type="primary" + link style="color: #ff4d4f" @click="removeFieldOptionItem(scope, scope.$index, 'constraint')" >移除</el-button @@ -174,7 +176,8 @@ > <el-divider direction="vertical" /> <el-button - type="text" + type="primary" + link style="color: #ff4d4f" @click="removeFieldOptionItem(scope, scope.$index, 'property')" >移除</el-button diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 176aba3b..05dc9f71 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -18,7 +18,8 @@ <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> <el-form-item prop="tenantName" v-if="loginData.tenantEnable === 'true'"> <el-input - type="text" + type="primary" + link v-model="loginData.loginForm.tenantName" :placeholder="t('login.tenantNamePlaceholder')" :prefix-icon="iconHouse" diff --git a/src/views/Login/components/MobileForm.vue b/src/views/Login/components/MobileForm.vue index 3a0ab686..6e8bdc47 100644 --- a/src/views/Login/components/MobileForm.vue +++ b/src/views/Login/components/MobileForm.vue @@ -19,7 +19,8 @@ <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> <el-form-item prop="tenantName" v-if="loginData.tenantEnable === 'true'"> <el-input - type="text" + type="primary" + link v-model="loginData.loginForm.tenantName" :placeholder="t('login.tenantNamePlaceholder')" :prefix-icon="iconHouse" diff --git a/src/views/bpm/definition/index.vue b/src/views/bpm/definition/index.vue index f5fff612..ae260b45 100644 --- a/src/views/bpm/definition/index.vue +++ b/src/views/bpm/definition/index.vue @@ -18,7 +18,8 @@ <template #default="scope"> <el-button v-if="scope.row.formType === 10" - type="text" + type="primary" + link @click="handleFormDetail(scope.row)" > <span>{{ scope.row.formName }}</span> diff --git a/src/views/bpm/model/index.vue b/src/views/bpm/model/index.vue index 48ddee12..5093e2b5 100644 --- a/src/views/bpm/model/index.vue +++ b/src/views/bpm/model/index.vue @@ -79,14 +79,16 @@ <template #default="scope"> <el-button v-if="scope.row.formType === 10" - type="text" + type="primary" + link @click="handleFormDetail(scope.row)" > <span>{{ scope.row.formName }}</span> </el-button> <el-button v-else-if="scope.row.formType === 20" - type="text" + type="primary" + link @click="handleFormDetail(scope.row)" > <span>{{ scope.row.formCustomCreatePath }}</span> diff --git a/src/views/mp/components/wx-reply/main.vue b/src/views/mp/components/wx-reply/main.vue index de515ae6..4768eb31 100644 --- a/src/views/mp/components/wx-reply/main.vue +++ b/src/views/mp/components/wx-reply/main.vue @@ -231,7 +231,7 @@ :on-success="handleUploadSuccess" > <template #trigger> - <el-button type="text">本地上传</el-button> + <el-button type="primary" link>本地上传</el-button> </template> <el-button type="primary" link @click="openMaterial" style="margin-left: 5px" >素材库选择 From c4746fc804a7fe127ce63d92de121076bdb91b58 Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 18:06:16 +0800 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=E5=B0=9D=E8=AF=95=E6=8B=86?= =?UTF-8?q?=E5=88=86=E3=80=90=E6=B6=88=E6=81=AF=E7=AE=A1=E7=90=86=E3=80=91?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/mp/message/DataGrid.vue | 147 ++++++++++++++++++++++++ src/views/mp/message/index.vue | 183 ++++++------------------------ 2 files changed, 179 insertions(+), 151 deletions(-) create mode 100644 src/views/mp/message/DataGrid.vue diff --git a/src/views/mp/message/DataGrid.vue b/src/views/mp/message/DataGrid.vue new file mode 100644 index 00000000..eaa85e5b --- /dev/null +++ b/src/views/mp/message/DataGrid.vue @@ -0,0 +1,147 @@ +<template> + <div> + <el-table v-loading="props.loading" :data="props.list"> + <el-table-column + label="发送时间" + align="center" + prop="createTime" + width="180" + :formatter="dateFormatter" + /> + <el-table-column label="消息类型" align="center" prop="type" width="80" /> + <el-table-column label="发送方" align="center" prop="sendFrom" width="80"> + <template #default="scope"> + <el-tag v-if="scope.row.sendFrom === 1" type="success">粉丝</el-tag> + <el-tag v-else type="info">公众号</el-tag> + </template> + </el-table-column> + <el-table-column label="用户标识" align="center" prop="openid" width="300" /> + <el-table-column label="内容" prop="content"> + <template #default="scope"> + <!-- 【事件】区域 --> + <div v-if="scope.row.type === MsgType.Event && scope.row.event === 'subscribe'"> + <el-tag type="success">关注</el-tag> + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'unsubscribe'"> + <el-tag type="danger">取消关注</el-tag> + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'CLICK'"> + <el-tag>点击菜单</el-tag> + 【{{ scope.row.eventKey }}】 + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'VIEW'"> + <el-tag>点击菜单链接</el-tag> + 【{{ scope.row.eventKey }}】 + </div> + <div + v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'scancode_waitmsg'" + > + <el-tag>扫码结果</el-tag> + 【{{ scope.row.eventKey }}】 + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'scancode_push'"> + <el-tag>扫码结果</el-tag> + 【{{ scope.row.eventKey }}】 + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_sysphoto'"> + <el-tag>系统拍照发图</el-tag> + </div> + <div + v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_photo_or_album'" + > + <el-tag>拍照或者相册</el-tag> + </div> + <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_weixin'"> + <el-tag>微信相册</el-tag> + </div> + <div + v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'location_select'" + > + <el-tag>选择地理位置</el-tag> + </div> + <div v-else-if="scope.row.type === MsgType.Event"> + <el-tag type="danger">未知事件类型</el-tag> + </div> + <!-- 【消息】区域 --> + <div v-else-if="scope.row.type === MsgType.Text">{{ scope.row.content }}</div> + <div v-else-if="scope.row.type === MsgType.Voice"> + <wx-voice-player :url="scope.row.mediaUrl" :content="scope.row.recognition" /> + </div> + <div v-else-if="scope.row.type === MsgType.Image"> + <a target="_blank" :href="scope.row.mediaUrl"> + <img :src="scope.row.mediaUrl" style="width: 100px" /> + </a> + </div> + <div v-else-if="scope.row.type === MsgType.Video || scope.row.type === 'shortvideo'"> + <wx-video-player :url="scope.row.mediaUrl" style="margin-top: 10px" /> + </div> + <div v-else-if="scope.row.type === MsgType.Link"> + <el-tag>链接</el-tag> + : + <a :href="scope.row.url" target="_blank">{{ scope.row.title }}</a> + </div> + <div v-else-if="scope.row.type === MsgType.Location"> + <WxLocation + :label="scope.row.label" + :location-y="scope.row.locationY" + :location-x="scope.row.locationX" + /> + </div> + <div v-else-if="scope.row.type === MsgType.Music"> + <WxMusic + :title="scope.row.title" + :description="scope.row.description" + :thumb-media-url="scope.row.thumbMediaUrl" + :music-url="scope.row.musicUrl" + :hq-music-url="scope.row.hqMusicUrl" + /> + </div> + <div v-else-if="scope.row.type === MsgType.News"> + <WxNews :articles="scope.row.articles" /> + </div> + <div v-else> + <el-tag type="danger">未知消息类型</el-tag> + </div> + </template> + </el-table-column> + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button + link + type="primary" + @click="emit('send', scope.row.userId)" + v-hasPermi="['mp:message:send']" + > + 消息 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页组件 --> + </div> +</template> + +<script setup lang="ts"> +import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue' +import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue' +import WxLocation from '@/views/mp/components/wx-location/main.vue' +import WxMusic from '@/views/mp/components/wx-music/main.vue' +import WxNews from '@/views/mp/components/wx-news/main.vue' +import { dateFormatter } from '@/utils/formatTime' +import { MsgType } from '@/views/mp/components/wx-msg/types' + +const props = defineProps({ + list: { + type: Array, + required: true + }, + loading: { + type: Boolean, + required: true + } +}) + +const emit = defineEmits<{ (e: 'send', v: number) }>() +</script> + +<style scoped></style> diff --git a/src/views/mp/message/index.vue b/src/views/mp/message/index.vue index 4ab19fda..ca7e0d7e 100644 --- a/src/views/mp/message/index.vue +++ b/src/views/mp/message/index.vue @@ -58,124 +58,7 @@ <!-- 列表 --> <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column - label="发送时间" - align="center" - prop="createTime" - width="180" - :formatter="dateFormatter" - /> - <el-table-column label="消息类型" align="center" prop="type" width="80" /> - <el-table-column label="发送方" align="center" prop="sendFrom" width="80"> - <template #default="scope"> - <el-tag v-if="scope.row.sendFrom === 1" type="success">粉丝</el-tag> - <el-tag v-else type="info">公众号</el-tag> - </template> - </el-table-column> - <el-table-column label="用户标识" align="center" prop="openid" width="300" /> - <el-table-column label="内容" prop="content"> - <template #default="scope"> - <!-- 【事件】区域 --> - <div v-if="scope.row.type === MsgType.Event && scope.row.event === 'subscribe'"> - <el-tag type="success">关注</el-tag> - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'unsubscribe'"> - <el-tag type="danger">取消关注</el-tag> - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'CLICK'"> - <el-tag>点击菜单</el-tag> - 【{{ scope.row.eventKey }}】 - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'VIEW'"> - <el-tag>点击菜单链接</el-tag> - 【{{ scope.row.eventKey }}】 - </div> - <div - v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'scancode_waitmsg'" - > - <el-tag>扫码结果</el-tag> - 【{{ scope.row.eventKey }}】 - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'scancode_push'"> - <el-tag>扫码结果</el-tag> - 【{{ scope.row.eventKey }}】 - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_sysphoto'"> - <el-tag>系统拍照发图</el-tag> - </div> - <div - v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_photo_or_album'" - > - <el-tag>拍照或者相册</el-tag> - </div> - <div v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'pic_weixin'"> - <el-tag>微信相册</el-tag> - </div> - <div - v-else-if="scope.row.type === MsgType.Event && scope.row.event === 'location_select'" - > - <el-tag>选择地理位置</el-tag> - </div> - <div v-else-if="scope.row.type === MsgType.Event"> - <el-tag type="danger">未知事件类型</el-tag> - </div> - <!-- 【消息】区域 --> - <div v-else-if="scope.row.type === MsgType.Text">{{ scope.row.content }}</div> - <div v-else-if="scope.row.type === MsgType.Voice"> - <wx-voice-player :url="scope.row.mediaUrl" :content="scope.row.recognition" /> - </div> - <div v-else-if="scope.row.type === MsgType.Image"> - <a target="_blank" :href="scope.row.mediaUrl"> - <img :src="scope.row.mediaUrl" style="width: 100px" /> - </a> - </div> - <div v-else-if="scope.row.type === MsgType.Video || scope.row.type === 'shortvideo'"> - <wx-video-player :url="scope.row.mediaUrl" style="margin-top: 10px" /> - </div> - <div v-else-if="scope.row.type === MsgType.Link"> - <el-tag>链接</el-tag> - : - <a :href="scope.row.url" target="_blank">{{ scope.row.title }}</a> - </div> - <div v-else-if="scope.row.type === MsgType.Location"> - <WxLocation - :label="scope.row.label" - :location-y="scope.row.locationY" - :location-x="scope.row.locationX" - /> - </div> - <div v-else-if="scope.row.type === MsgType.Music"> - <WxMusic - :title="scope.row.title" - :description="scope.row.description" - :thumb-media-url="scope.row.thumbMediaUrl" - :music-url="scope.row.musicUrl" - :hq-music-url="scope.row.hqMusicUrl" - /> - </div> - <div v-else-if="scope.row.type === MsgType.News"> - <WxNews :articles="scope.row.articles" /> - </div> - <div v-else> - <el-tag type="danger">未知消息类型</el-tag> - </div> - </template> - </el-table-column> - <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> - <template #default="scope"> - <el-button - link - type="primary" - @click="handleSend(scope.row)" - v-hasPermi="['mp:message:send']" - > - 消息 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页组件 --> + <DataGrid :list="list" :loading="loading" @send="handleSend" /> <Pagination v-show="total > 0" :total="total" @@ -183,36 +66,31 @@ v-model:limit="queryParams.pageSize" @pagination="getList" /> - - <!-- 发送消息的弹窗 --> - <el-dialog - title="粉丝消息列表" - v-model="showMessageBox" - @click="showMessageBox = true" - width="50%" - destroy-on-close - > - <WxMsg :user-id="userId" /> - </el-dialog> </ContentWrap> + + <!-- 发送消息的弹窗 --> + <el-dialog + title="粉丝消息列表" + v-model="messageBox.show" + @click="messageBox.show = true" + width="50%" + destroy-on-close + > + <WxMsg :user-id="messageBox.userId" /> + </el-dialog> </template> <script setup lang="ts" name="MpMessage"> -import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue' -import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue' -import WxMsg from '@/views/mp/components/wx-msg/main.vue' -import WxLocation from '@/views/mp/components/wx-location/main.vue' -import WxMusic from '@/views/mp/components/wx-music/main.vue' -import WxNews from '@/views/mp/components/wx-news/main.vue' -import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' import * as MpMessageApi from '@/api/mp/message' +import WxMsg from '@/views/mp/components/wx-msg/main.vue' +import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue' +import DataGrid from './DataGrid.vue' import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' import { MsgType } from '@/views/mp/components/wx-msg/types' import type { FormInstance } from 'element-plus' -const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 -const list = ref<any[]>([]) // 列表的数据 +const loading = ref(false) +const total = ref(0) // 数据的总页数 +const list = ref<any[]>([]) // 当前页的列表数据 // 搜索参数 interface QueryParams { @@ -232,8 +110,12 @@ const queryParams: QueryParams = reactive({ createTime: [] }) const queryFormRef = ref<FormInstance | null>(null) // 搜索的表单 -const showMessageBox = ref(false) // 是否显示弹出层 -const userId = ref(0) // 操作的用户编号 + +// 消息对话框 +const messageBox = reactive({ + show: false, + userId: 0 +}) /** 侦听accountId */ const onAccountChanged = (id?: number) => { @@ -242,6 +124,11 @@ const onAccountChanged = (id?: number) => { } /** 查询列表 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + const getList = async () => { try { loading.value = true @@ -253,12 +140,6 @@ const getList = async () => { } } -/** 搜索按钮操作 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - /** 重置按钮操作 */ const resetQuery = async () => { // 暂存accountId,并在reset后恢复 @@ -269,8 +150,8 @@ const resetQuery = async () => { } /** 打开消息发送窗口 */ -const handleSend = async (row: any) => { - userId.value = row.userId - showMessageBox.value = true +const handleSend = async (userId: number) => { + messageBox.userId = userId + messageBox.show = true } </script> From 5f1aa869120be878c3aca03648b799b02e95b18c Mon Sep 17 00:00:00 2001 From: dhb52 <dhb52@126.com> Date: Fri, 14 Apr 2023 19:43:50 +0800 Subject: [PATCH 9/9] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4quill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 1d020d6d..1401347d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@form-create/element-ui": "^3.1.17", "@iconify/iconify": "^3.1.0", "@videojs-player/vue": "^1.0.0", - "@vueup/vue-quill": "^1.1.1", "@vueuse/core": "^9.13.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10",