diff --git a/package.json b/package.json index dce5244d..1a836c5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yudao-ui-admin-vue3", - "version": "1.7.1-snapshot.1961", + "version": "1.7.2-snapshot", "description": "基于vue3、vite4、element-plus、typesScript", "author": "xingyu", "private": false, diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index d3b18d9c..55e933ed 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -272,7 +272,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ { path: '/manager/task-assign-rule', component: () => import('@/views/bpm/taskAssignRule/index.vue'), - name: 'BpmTaskAssignRule', + name: 'BpmTaskAssignRuleList', meta: { noCache: true, hidden: true, diff --git a/src/utils/routerHelper.ts b/src/utils/routerHelper.ts index af6a9c3c..a6825653 100644 --- a/src/utils/routerHelper.ts +++ b/src/utils/routerHelper.ts @@ -1,10 +1,22 @@ +import type { RouteLocationNormalized, Router, RouteRecordNormalized } from 'vue-router' import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' -import type { Router, RouteLocationNormalized, RouteRecordNormalized } from 'vue-router' import { isUrl } from '@/utils/is' -import { omit, cloneDeep } from 'lodash-es' +import { cloneDeep, omit } from 'lodash-es' const modules = import.meta.glob('../views/**/*.{vue,tsx}') - +/** + * 注册一个异步组件 + * @param componentPath 例:/bpm/oa/leave/detail + */ +export const registerComponent = (componentPath: string) => { + for (const item in modules) { + if (item.includes(componentPath)) { + // 使用异步组件的方式来动态加载组件 + // @ts-ignore + return defineAsyncComponent(modules[item]) + } + } +} /* Layout */ export const Layout = () => import('@/layout/Layout.vue') diff --git a/src/views/bpm/form/editor/index.vue b/src/views/bpm/form/editor/index.vue index c56a7747..f11c1228 100644 --- a/src/views/bpm/form/editor/index.vue +++ b/src/views/bpm/form/editor/index.vue @@ -44,10 +44,13 @@ import { CommonStatusEnum } from '@/utils/constants' import * as FormApi from '@/api/bpm/form' import FcDesigner from '@form-create/designer' import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate' +import { useTagsViewStore } from '@/store/modules/tagsView' const { t } = useI18n() // 国际化 const message = useMessage() // 消息 -const { query } = useRoute() // 路由 +const { push, currentRoute } = useRouter() // 路由 +const { query } = useRoute() // 路由信息 +const { delView } = useTagsViewStore() // 视图操作 const designer = ref() // 表单设计器 const dialogVisible = ref(false) // 弹窗是否展示 @@ -88,10 +91,16 @@ const submitForm = async () => { message.success(t('common.updateSuccess')) } dialogVisible.value = false + close() } finally { formLoading.value = false } } +/** 关闭按钮 */ +const close = () => { + delView(unref(currentRoute)) + push('/bpm/manager/form') +} /** 初始化 **/ onMounted(async () => { diff --git a/src/views/bpm/form/index.vue b/src/views/bpm/form/index.vue index 915bd0bd..48bb3698 100644 --- a/src/views/bpm/form/index.vue +++ b/src/views/bpm/form/index.vue @@ -2,26 +2,33 @@ - 搜索 - 重置 - - 新增 + + + 搜索 + + + + 重置 + + + + 新增 @@ -30,38 +37,38 @@ - - - + + + - + - + - diff --git a/src/views/mp/autoReply/components/ReplyTable.vue b/src/views/mp/autoReply/components/ReplyTable.vue new file mode 100644 index 00000000..0b739cef --- /dev/null +++ b/src/views/mp/autoReply/components/ReplyTable.vue @@ -0,0 +1,115 @@ + + diff --git a/src/views/mp/autoReply/components/types.ts b/src/views/mp/autoReply/components/types.ts new file mode 100644 index 00000000..0d78fd85 --- /dev/null +++ b/src/views/mp/autoReply/components/types.ts @@ -0,0 +1,48 @@ +// 消息类型(Follow: 关注时回复;Message: 消息回复;Keyword: 关键词回复) +// 作为 tab.name,enum 的数字不能随意修改,与 api 参数相关 +export enum MsgType { + Follow = 1, + Message = 2, + Keyword = 3 +} + +type ReplyType = 'text' | 'image' | 'voice' | 'video' | 'shortvideo' | 'location' | 'link' + +export interface ReplyForm { + // relation: + id?: number + accountId?: number + type?: MsgType + // request: + requestMessageType?: ReplyType + requestMatch?: number + requestKeyword?: string + // response: + responseMessageType?: ReplyType + responseContent?: string + responseMediaId?: number + responseMediaUrl?: string + responseTitle?: string + responseDescription?: number + responseThumbMediaId?: string + responseThumbMediaUrl?: string + responseArticles?: any[] + responseMusicUrl?: string + responseHqMusicUrl?: string +} + +// TODO @Dhb52:ObjData 这个类名可以在看看,ObjData 有点通用 +export interface ObjData { + type: ReplyType + accountId?: number + content?: string + mediaId?: number + url?: string + title?: string + description?: string + thumbMediaId?: number + thumbMediaUrl?: string + articles?: any[] + musicUrl?: string + hqMusicUrl?: string +} diff --git a/src/views/mp/autoReply/index.vue b/src/views/mp/autoReply/index.vue index 0fd6001d..2d9b492d 100644 --- a/src/views/mp/autoReply/index.vue +++ b/src/views/mp/autoReply/index.vue @@ -12,14 +12,14 @@ - + @@ -30,117 +30,32 @@ - - - - - - - - - - - - - - - - - + - + + @@ -156,7 +71,7 @@ diff --git a/src/views/mp/components/wx-account-select/main.vue b/src/views/mp/components/wx-account-select/main.vue index 110fc8a5..5359b366 100644 --- a/src/views/mp/components/wx-account-select/main.vue +++ b/src/views/mp/components/wx-account-select/main.vue @@ -22,11 +22,14 @@ const handleQuery = async () => { // 默认选中第一个 if (accountList.value.length > 0) { account.id = accountList.value[0].id + account.name = accountList.value[0].name emit('change', account.id, account.name) } } -const onChanged = () => { +const onChanged = (id?: number) => { + const found = accountList.value.find((v) => v.id === id) + account.name = found ? found.name : '' emit('change', account.id, account.name) } diff --git a/src/views/mp/components/wx-location/main.vue b/src/views/mp/components/wx-location/main.vue index 17598136..7f1333ee 100644 --- a/src/views/mp/components/wx-location/main.vue +++ b/src/views/mp/components/wx-location/main.vue @@ -1,5 +1,5 @@ @@ -231,12 +231,8 @@ const sendMsg = async () => { list.value = [...list.value, ...[data]] scrollToBottom() - //ts检查的時候会判断这个组件可能是空的,所以需要进行断言。 - //避免 tab 的数据未清理 - const deleteObj = replySelectRef.value?.deleteObj - if (deleteObj) { - deleteObj() - } + // 发送后清空数据 + replySelectRef.value?.clear() } const loadingMore = () => { @@ -333,6 +329,7 @@ const scrollToBottom = () => { .send-but { float: right; - margin-top: 8px !important; + margin-top: 8px; + margin-bottom: 8px; } diff --git a/src/views/mp/components/wx-reply/components/TabImage.vue b/src/views/mp/components/wx-reply/components/TabImage.vue new file mode 100644 index 00000000..eecc24cb --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabImage.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/src/views/mp/components/wx-reply/components/TabMusic.vue b/src/views/mp/components/wx-reply/components/TabMusic.vue new file mode 100644 index 00000000..2c3b04e5 --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabMusic.vue @@ -0,0 +1,119 @@ + + + diff --git a/src/views/mp/components/wx-reply/components/TabNews.vue b/src/views/mp/components/wx-reply/components/TabNews.vue new file mode 100644 index 00000000..bb9272e7 --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabNews.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/views/mp/components/wx-reply/components/TabText.vue b/src/views/mp/components/wx-reply/components/TabText.vue new file mode 100644 index 00000000..bd7b0187 --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabText.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/views/mp/components/wx-reply/components/TabVideo.vue b/src/views/mp/components/wx-reply/components/TabVideo.vue new file mode 100644 index 00000000..c924bc2a --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabVideo.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/views/mp/components/wx-reply/components/TabVoice.vue b/src/views/mp/components/wx-reply/components/TabVoice.vue new file mode 100644 index 00000000..6d40a052 --- /dev/null +++ b/src/views/mp/components/wx-reply/components/TabVoice.vue @@ -0,0 +1,160 @@ + + + + diff --git a/src/views/mp/components/wx-reply/components/types.ts b/src/views/mp/components/wx-reply/components/types.ts new file mode 100644 index 00000000..d5273334 --- /dev/null +++ b/src/views/mp/components/wx-reply/components/types.ts @@ -0,0 +1,25 @@ +type ReplyType = '' | 'news' | 'image' | 'voice' | 'video' | 'music' | 'text' + +interface ObjData { + accountId: number + type: ReplyType + name: string | null + content: string | null + mediaId: string | null + url: string | null + title: string | null + description: string | null + thumbMediaId: string | null + thumbMediaUrl: string | null + musicUrl: string | null + hqMusicUrl: string | null + introduction: string | null + articles: any[] +} + +enum NewsType { + Published = '1', + Draft = '2' +} + +export { ObjData, NewsType } diff --git a/src/views/mp/components/wx-reply/main.vue b/src/views/mp/components/wx-reply/main.vue index 4768eb31..b00e4345 100644 --- a/src/views/mp/components/wx-reply/main.vue +++ b/src/views/mp/components/wx-reply/main.vue @@ -8,607 +8,64 @@ ④ 支持发送【视频】消息时,支持新建视频 --> - diff --git a/src/views/mp/draft/components/DraftTable.vue b/src/views/mp/draft/components/DraftTable.vue new file mode 100644 index 00000000..63cee31f --- /dev/null +++ b/src/views/mp/draft/components/DraftTable.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/views/mp/draft/components/NewsForm.vue b/src/views/mp/draft/components/NewsForm.vue new file mode 100644 index 00000000..a2b88a5b --- /dev/null +++ b/src/views/mp/draft/components/NewsForm.vue @@ -0,0 +1,302 @@ + + + + + diff --git a/src/views/mp/draft/components/index.ts b/src/views/mp/draft/components/index.ts new file mode 100644 index 00000000..51e843d3 --- /dev/null +++ b/src/views/mp/draft/components/index.ts @@ -0,0 +1,7 @@ +import type { Article, NewsItem, NewsItemList } from './types' +import { createEmptyNewsItem } from './types' +import DraftTable from './DraftTable.vue' +import NewsForm from './NewsForm.vue' + +export { DraftTable, NewsForm, createEmptyNewsItem } +export type { Article, NewsItem, NewsItemList } diff --git a/src/views/mp/draft/components/types.ts b/src/views/mp/draft/components/types.ts new file mode 100644 index 00000000..a8cf00c3 --- /dev/null +++ b/src/views/mp/draft/components/types.ts @@ -0,0 +1,40 @@ +interface NewsItem { + title: string + thumbMediaId: string + author: string + digest: string + showCoverPic: string + content: string + contentSourceUrl: string + needOpenComment: string + onlyFansCanComment: string + thumbUrl: string +} + +interface NewsItemList { + newsItem: NewsItem[] +} + +interface Article { + mediaId: string + content: NewsItemList + updateTime: number +} + +const createEmptyNewsItem = (): NewsItem => { + return { + title: '', + thumbMediaId: '', + author: '', + digest: '', + showCoverPic: '', + content: '', + contentSourceUrl: '', + needOpenComment: '', + onlyFansCanComment: '', + thumbUrl: '' + } +} + +export type { Article, NewsItem, NewsItemList } +export { createEmptyNewsItem } diff --git a/src/views/mp/draft/index.vue b/src/views/mp/draft/index.vue index cf0bb10d..7de992cd 100644 --- a/src/views/mp/draft/index.vue +++ b/src/views/mp/draft/index.vue @@ -14,7 +14,13 @@ - + 新增 @@ -23,40 +29,13 @@ -
- -
+
-
- - - - -
-
-
-
- -
{{ news.title }}
-
-
- 下移 - 删除 - -
-
-
-
-
{{ news.title }}
-
- -
-
-
- 下移 - - 上移 - 删除 - -
-
-
- - - - - -
-
- -
- - - - - - - - - -

封面:

-
- - -
- - - 素材库选择 - - -
- - - -
-
- -

摘要:

- -
-
- - - - -
-
-
- -
-
+ + + + + + + diff --git a/src/views/mp/hooks/useUpload.ts b/src/views/mp/hooks/useUpload.ts new file mode 100644 index 00000000..b2d32d71 --- /dev/null +++ b/src/views/mp/hooks/useUpload.ts @@ -0,0 +1,50 @@ +import type { UploadRawFile } from 'element-plus' + +const message = useMessage() // 消息 + +enum MaterialType { + Image = 'image', + Voice = 'voice', + Video = 'video' +} + +const useBeforeUpload = (type: MaterialType, maxSizeMB: number) => { + const fn = (rawFile: UploadRawFile): boolean => { + let allowTypes: string[] = [] + let name = '' + + switch (type) { + case MaterialType.Image: + allowTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/jpg'] + maxSizeMB = 2 + name = '图片' + break + case MaterialType.Voice: + allowTypes = ['audio/mp3', 'audio/mpeg', 'audio/wma', 'audio/wav', 'audio/amr'] + maxSizeMB = 2 + name = '语音' + break + case MaterialType.Video: + allowTypes = ['video/mp4'] + maxSizeMB = 10 + name = '视频' + break + } + // 格式不正确 + if (!allowTypes.includes(rawFile.type)) { + message.error(`上传${name}格式不对!`) + return false + } + // 大小不正确 + if (rawFile.size / 1024 / 1024 > maxSizeMB) { + message.error(`上传${name}大小不能超过${maxSizeMB}M!`) + return false + } + + return true + } + + return fn +} + +export { MaterialType, useBeforeUpload } diff --git a/src/views/mp/material/components/UploadFile.vue b/src/views/mp/material/components/UploadFile.vue index 3ab62224..be7e323b 100644 --- a/src/views/mp/material/components/UploadFile.vue +++ b/src/views/mp/material/components/UploadFile.vue @@ -6,12 +6,13 @@ :limit="1" :file-list="fileList" :data="uploadData" - :on-progress="() => (uploading = true)" - :before-upload="beforeUpload" - :on-success="handleUploadSuccess" + :on-progress="(isUploading = true)" + :on-error="onUploadError" + :before-upload="onBeforeUpload" + :on-success="onUploadSuccess" > - - {{ uploading ? '正在上传' : '点击上传' }} + + {{ isUploading ? '正在上传' : '点击上传' }} + @@ -513,9 +294,9 @@ const deleteMaterial = () => { } .clearfix::after { - content: ''; display: table; clear: both; + content: ''; } div { @@ -523,116 +304,50 @@ div { } .weixin-hd { - color: #fff; - text-align: center; position: relative; bottom: 426px; - left: 0px; + left: 0; width: 300px; height: 64px; + color: #fff; + text-align: center; 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; + left: 0; + width: 100%; + font-size: 14px; + color: #fff; + text-align: center; } .weixin-menu { - background: transparent url('./assets/menu_foot.png') no-repeat 0 0; padding-left: 43px; font-size: 12px; -} - -.menu_option { - width: 40% !important; + background: transparent url('./assets/menu_foot.png') no-repeat 0 0; } .public-account-management { - min-width: 1200px; width: 1200px; + // min-width: 1200px; margin: 0 auto; .left { - float: left; + position: relative; display: inline-block; + float: left; width: 350px; height: 715px; + padding: 518px 25px 88px; 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; @@ -644,85 +359,29 @@ div { } } - /*右边菜单内容*/ + /* 右边菜单内容 */ .right { float: left; width: 63%; - background-color: #e8e7e7; padding: 20px; margin-left: 20px; - -webkit-box-sizing: border-box; + background-color: #e8e7e7; + 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%; } } diff --git a/src/views/system/notify/template/index.vue b/src/views/system/notify/template/index.vue index 6d1938ad..12392b8a 100644 --- a/src/views/system/notify/template/index.vue +++ b/src/views/system/notify/template/index.vue @@ -212,7 +212,7 @@ const handleDelete = async (id: number) => { // 删除的二次确认 await message.delConfirm() // 发起删除 - await NotifyTemplateApi.deleteNotifyTemplateApi(id) + await NotifyTemplateApi.deleteNotifyTemplate(id) message.success('删除成功') // 刷新列表 await getList() diff --git a/src/views/system/role/RoleAssignMenuForm.vue b/src/views/system/role/RoleAssignMenuForm.vue index 9b7d5a15..cfd30842 100644 --- a/src/views/system/role/RoleAssignMenuForm.vue +++ b/src/views/system/role/RoleAssignMenuForm.vue @@ -91,6 +91,7 @@ const open = async (row: RoleApi.RoleVO) => { defineExpose({ open }) // 提供 open 方法,用于打开弹窗 /** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const submitForm = async () => { // 校验表单 if (!formRef) return @@ -109,6 +110,8 @@ const submitForm = async () => { await PermissionApi.assignRoleMenu(data) message.success(t('common.updateSuccess')) dialogVisible.value = false + // 发送操作成功的事件 + emit('success') } finally { formLoading.value = false } diff --git a/src/views/system/role/RoleDataPermissionForm.vue b/src/views/system/role/RoleDataPermissionForm.vue index 87a33e6c..279ba973 100644 --- a/src/views/system/role/RoleDataPermissionForm.vue +++ b/src/views/system/role/RoleDataPermissionForm.vue @@ -107,6 +107,7 @@ const open = async (row: RoleApi.RoleVO) => { defineExpose({ open }) // 提供 open 方法,用于打开弹窗 /** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const submitForm = async () => { formLoading.value = true try { @@ -121,6 +122,8 @@ const submitForm = async () => { await PermissionApi.assignRoleDataScope(data) message.success(t('common.updateSuccess')) dialogVisible.value = false + // 发送操作成功的事件 + emit('success') } finally { formLoading.value = false } diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue index 4df19ef8..e7b8158b 100644 --- a/src/views/system/role/index.vue +++ b/src/views/system/role/index.vue @@ -156,9 +156,9 @@ - + - +