review:【antd】【mp】图文草稿箱
This commit is contained in:
@@ -149,6 +149,7 @@ const showCreateButton = computed(() => {
|
||||
return tableDataLength.value <= 0;
|
||||
});
|
||||
|
||||
// TODO @hw:看看能不能参考 tag/index.vue 简化下
|
||||
/** 页面挂载后,等待表单初始化完成再加载数据 */
|
||||
onMounted(async () => {
|
||||
// 等待 WxAccountSelect 组件加载并设置默认值
|
||||
|
||||
@@ -13,8 +13,6 @@ import { Button, Image, message, Modal, Upload } from 'ant-design-vue';
|
||||
import { UploadType, useBeforeUpload } from '#/utils/useUpload';
|
||||
import { WxMaterialSelect } from '#/views/mp/modules/wx-material-select';
|
||||
|
||||
// 设置上传的请求头部
|
||||
|
||||
const props = defineProps<{
|
||||
isFirst: boolean;
|
||||
modelValue: NewsItem;
|
||||
@@ -54,10 +52,11 @@ function onMaterialSelected(item: any) {
|
||||
newsItem.value.thumbMediaId = item.mediaId;
|
||||
newsItem.value.thumbUrl = item.url;
|
||||
}
|
||||
|
||||
// TODO @hw:注释都补充下哈;
|
||||
const onBeforeUpload = (file: UploadFile) =>
|
||||
useBeforeUpload(UploadType.Image, 2)(file as any);
|
||||
|
||||
// TODO @hw:注释都补充下哈;
|
||||
function onUploadChange(info: any) {
|
||||
if (info.file.status === 'done') {
|
||||
onUploadSuccess(info.file.response || info.file);
|
||||
@@ -66,6 +65,7 @@ function onUploadChange(info: any) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @hw:注释都补充下哈;
|
||||
function onUploadSuccess(res: any) {
|
||||
if (res.code !== 0) {
|
||||
message.error(`上传出错:${res.msg}`);
|
||||
@@ -74,12 +74,12 @@ function onUploadSuccess(res: any) {
|
||||
|
||||
// 重置上传文件的表单
|
||||
fileList.value = [];
|
||||
|
||||
// 设置草稿的封面字段
|
||||
newsItem.value.thumbMediaId = res.data.mediaId;
|
||||
newsItem.value.thumbUrl = res.data.url;
|
||||
}
|
||||
|
||||
// TODO @hw:注释都补充下哈;
|
||||
function onUploadError(err: Error) {
|
||||
message.error(`上传失败: ${err.message}`);
|
||||
}
|
||||
@@ -88,6 +88,7 @@ function onUploadError(err: Error) {
|
||||
<template>
|
||||
<div>
|
||||
<p>封面:</p>
|
||||
<!-- TODO @hw:我貌似上传不成功。不确定是不是我这边的问题;;;可以微信沟通下哈。 -->
|
||||
<div class="thumb-div">
|
||||
<Image
|
||||
v-if="newsItem.thumbUrl"
|
||||
@@ -115,6 +116,7 @@ function onUploadError(err: Error) {
|
||||
<Button size="small" type="primary">本地上传</Button>
|
||||
</template>
|
||||
</Upload>
|
||||
<!-- TODO @hw:tindwind -->
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
@@ -146,6 +148,7 @@ function onUploadError(err: Error) {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/** TODO @hw:尽量使用 tindwind 替代。ps:如果多个组件复用,那就不用调整 */
|
||||
.upload-tip {
|
||||
margin-top: 5px;
|
||||
margin-left: 5px;
|
||||
|
||||
@@ -20,7 +20,6 @@ const props = defineProps<{
|
||||
modelValue: NewsItem[] | null;
|
||||
}>();
|
||||
|
||||
// v-model=newsList
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: NewsItem[]): void;
|
||||
}>();
|
||||
@@ -45,6 +44,7 @@ const activeNewsItem = computed(() => {
|
||||
return item;
|
||||
});
|
||||
|
||||
// TODO @hw:注释使用 /** */
|
||||
// 将图文向下移动
|
||||
function moveDownNews(index: number) {
|
||||
const current = newsList.value[index];
|
||||
@@ -69,14 +69,10 @@ function moveUpNews(index: number) {
|
||||
|
||||
// 删除指定 index 的图文
|
||||
async function removeNews(index: number) {
|
||||
try {
|
||||
await confirm('确定删除该图文吗?');
|
||||
newsList.value.splice(index, 1);
|
||||
if (activeNewsIndex.value === index) {
|
||||
activeNewsIndex.value = 0;
|
||||
}
|
||||
} catch {
|
||||
// empty
|
||||
await confirm('确定删除该图文吗?');
|
||||
newsList.value.splice(index, 1);
|
||||
if (activeNewsIndex.value === index) {
|
||||
activeNewsIndex.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +230,7 @@ function plusNews() {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/** TODO @hw:尽量使用 tindwind 替代。ps:如果多个组件复用,那就不用调整 */
|
||||
.ope-row {
|
||||
padding-top: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO @hw:要不把 components 里的部分,拿到 modules 里。
|
||||
interface NewsItem {
|
||||
title: string;
|
||||
thumbMediaId: string;
|
||||
|
||||
@@ -30,6 +30,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
// TODO @hw:这里的公众号选择,要改参考 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/mp/tag/data.ts;相关联的代码还简单点~
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import { nextTick, onMounted, provide, ref, watch } from 'vue';
|
||||
|
||||
import { confirm, DocAlert, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
@@ -25,6 +26,7 @@ const [FormModal, formModalApi] = useVbenModal({
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
// TODO @hw:下面的方法,放到这个前面,和别的保持一致;
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
@@ -47,6 +49,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
...formValues,
|
||||
});
|
||||
// 处理 API 返回的数据,兼容不同的数据结构
|
||||
// TODO @wx:看 yudao-ui-admin-vue3/src/views/mp/draft/index.vue 项目里,转换没这么复杂。。。是不是这里有办法简化下?
|
||||
const formattedList: Article[] = drafts.list.map((draft: any) => {
|
||||
// 如果已经是 content.newsItem 格式,直接使用
|
||||
if (draft.content?.newsItem) {
|
||||
@@ -116,9 +119,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
});
|
||||
|
||||
// 提供 accountId 给子组件
|
||||
// TODO @hw:参考 tag/index.vue 放到 formValues.accountId;
|
||||
const accountId = ref<number>(-1);
|
||||
|
||||
// 监听表单提交,更新 accountId
|
||||
// TODO @hw:看看这个 watch、provide 能不能简化掉;
|
||||
watch(
|
||||
() => gridApi.formApi?.getLatestSubmissionValues?.()?.accountId,
|
||||
(newAccountId) => {
|
||||
@@ -138,7 +143,6 @@ async function handleCreate() {
|
||||
message.warning('请先选择公众号');
|
||||
return;
|
||||
}
|
||||
|
||||
formModalApi
|
||||
.setData({
|
||||
isCreating: true,
|
||||
@@ -156,7 +160,6 @@ async function handleEdit(row: Article) {
|
||||
message.warning('请先选择公众号');
|
||||
return;
|
||||
}
|
||||
|
||||
formModalApi
|
||||
.setData({
|
||||
isCreating: false,
|
||||
@@ -171,30 +174,27 @@ async function handleEdit(row: Article) {
|
||||
async function handlePublish(row: Article) {
|
||||
const formValues = await gridApi.formApi.getValues();
|
||||
const accountId = formValues.accountId;
|
||||
// TODO @hw:看看能不能去掉 -1 的判断哈?
|
||||
if (!accountId || accountId === -1) {
|
||||
message.warning('请先选择公众号');
|
||||
return;
|
||||
}
|
||||
|
||||
const content =
|
||||
await confirm(
|
||||
'你正在通过发布的方式发表内容。 发布不占用群发次数,一天可多次发布。' +
|
||||
'已发布内容不会推送给用户,也不会展示在公众号主页中。 ' +
|
||||
'发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。';
|
||||
'已发布内容不会推送给用户,也不会展示在公众号主页中。 ' +
|
||||
'发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。',
|
||||
);
|
||||
const hideLoading = message.loading({
|
||||
content: '发布中...',
|
||||
duration: 0,
|
||||
});
|
||||
// TODO @hw:MpFreePublishApi 去掉,直接 import;参考别的模块哈;
|
||||
try {
|
||||
await confirm(content);
|
||||
const hideLoading = message.loading({
|
||||
content: '发布中...',
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await MpFreePublishApi.submitFreePublish(accountId, row.mediaId);
|
||||
message.success('发布成功');
|
||||
await gridApi.query();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
} catch {
|
||||
//
|
||||
await MpFreePublishApi.submitFreePublish(accountId, row.mediaId);
|
||||
message.success('发布成功');
|
||||
await gridApi.query();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,25 +206,21 @@ async function handleDelete(row: Article) {
|
||||
message.warning('请先选择公众号');
|
||||
return;
|
||||
}
|
||||
|
||||
await confirm('此操作将永久删除该草稿, 是否继续?');
|
||||
const hideLoading = message.loading({
|
||||
content: '删除中...',
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await confirm('此操作将永久删除该草稿, 是否继续?');
|
||||
const hideLoading = message.loading({
|
||||
content: '删除中...',
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await MpDraftApi.deleteDraft(accountId, row.mediaId);
|
||||
message.success('删除成功');
|
||||
await gridApi.query();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
} catch {
|
||||
//
|
||||
await MpDraftApi.deleteDraft(accountId, row.mediaId);
|
||||
message.success('删除成功');
|
||||
await gridApi.query();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @hw:看看能不能参考 tag/index.vue 简化下
|
||||
// 页面挂载后,等待表单初始化完成再加载数据
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
@@ -243,6 +239,7 @@ onMounted(async () => {
|
||||
<Page auto-content-height>
|
||||
<DocAlert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" />
|
||||
|
||||
<!-- TODO @hw:参考别的模块 @success 调用 refresh 方法; -->
|
||||
<FormModal
|
||||
@success="
|
||||
() => {
|
||||
@@ -256,7 +253,7 @@ onMounted(async () => {
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '新增',
|
||||
label: $t('ui.actionTitle.create', ['图文草稿']),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['mp:draft:create'],
|
||||
|
||||
@@ -15,12 +15,15 @@ const emit = defineEmits(['success']);
|
||||
|
||||
const formData = ref<{
|
||||
accountId: number;
|
||||
// TODO @hw:是不是通过 id 字段判断是否为新增?类似 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/system/user/modules/form.vue
|
||||
isCreating: boolean;
|
||||
mediaId?: string;
|
||||
newsList?: NewsItem[];
|
||||
}>();
|
||||
const newsList = ref<NewsItem[]>([]);
|
||||
// TODO @hw:不需要 isSave,通过 modal 去 lock 就好啦。
|
||||
const isSubmitting = ref(false);
|
||||
// TODO @hw:不需要 isSave,通过 modal 去 lock 就好啦。
|
||||
const isSaved = ref(false);
|
||||
|
||||
const getTitle = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user