fix: 新分支迁移mp

This commit is contained in:
hw
2025-11-25 14:42:56 +08:00
parent f22b390380
commit b4c77f5498
29 changed files with 320 additions and 483 deletions

View File

@@ -93,7 +93,7 @@ function onUploadError(err: Error) {
/>
<IconifyIcon
v-else
icon="ep:plus"
icon="lucide:plus"
class="border border-[#d9d9d9] text-center text-[28px] leading-[120px] text-[#8c939d]"
:class="isFirst ? 'h-[120px] w-[230px]' : 'h-[120px] w-[120px]'"
/>

View File

@@ -1,32 +1,27 @@
<script lang="ts" setup>
import type { NewsItem } from './types';
import type { MpDraftApi } from '#/api/mp/draft';
import { computed, provide, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { ElMessage, ElMessageBox } from 'element-plus';
import { ElMessage } from 'element-plus';
import * as MpDraftApi from '#/api/mp/draft';
import { createDraft, updateDraft } from '#/api/mp/draft';
import NewsForm from './news-form.vue';
const emit = defineEmits(['success']);
// TODO @hw代码风格要和对应的 antd index.vue 一致,类似方法的顺序,注释等。原因是,这样后续两端迭代,会方便很多。
const formData = ref<{
accountId: number;
isCreating: boolean;
mediaId?: string;
newsList?: NewsItem[];
newsList?: MpDraftApi.NewsItem[];
}>();
const newsList = ref<NewsItem[]>([]);
const isSubmitting = ref(false);
const isSaved = ref(false);
const newsList = ref<MpDraftApi.NewsItem[]>([]);
const getTitle = computed(() => {
return formData.value?.isCreating ? '新建图文' : '修改图文';
return formData.value?.mediaId ? '修改图文' : '新建图文';
});
// 提供 accountId 给子组件
@@ -39,59 +34,45 @@ const [Modal, modalApi] = useVbenModal({
if (!formData.value) {
return;
}
isSubmitting.value = true;
modalApi.lock();
try {
if (formData.value.isCreating) {
await MpDraftApi.createDraft(formData.value.accountId, newsList.value);
ElMessage.success('新增成功');
} else if (formData.value.mediaId) {
await MpDraftApi.updateDraft(
if (formData.value.mediaId) {
await updateDraft(
formData.value.accountId,
formData.value.mediaId,
newsList.value,
);
ElMessage.success('更新成功');
} else {
await createDraft(formData.value.accountId, newsList.value);
ElMessage.success('新增成功');
}
isSaved.value = true;
await modalApi.close();
emit('success');
} finally {
isSubmitting.value = false;
modalApi.unlock();
}
},
async onBeforeClose() {
// 如果已经成功保存,直接关闭,不显示提示
if (isSaved.value) {
return true;
}
try {
await ElMessageBox.confirm('修改内容可能还未保存,确定关闭吗?');
return true;
} catch {
return false;
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
newsList.value = [];
isSaved.value = false;
return;
}
isSaved.value = false;
const data = modalApi.getData<{
accountId: number;
isCreating: boolean;
mediaId?: string;
newsList?: NewsItem[];
newsList?: MpDraftApi.NewsItem[];
}>();
if (!data) {
return;
}
formData.value = data;
formData.value = {
accountId: data.accountId,
mediaId: data.mediaId,
newsList: data.newsList,
};
newsList.value = data.newsList || [];
},
});
@@ -102,8 +83,7 @@ const [Modal, modalApi] = useVbenModal({
<NewsForm
v-if="formData"
v-model="newsList"
v-loading="isSubmitting"
:is-creating="formData.isCreating"
:is-creating="!formData.mediaId"
/>
</Modal>
</template>

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { NewsItem } from './types';
import type { MpDraftApi } from '#/api/mp/draft';
import { computed, ref } from 'vue';
@@ -16,24 +16,23 @@ import {
ElRow,
} from 'element-plus';
import { createEmptyNewsItem } from '#/api/mp/draft';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import CoverSelect from './cover-select.vue';
import { createEmptyNewsItem } from './types';
defineOptions({ name: 'NewsForm' });
const props = defineProps<{
isCreating: boolean;
modelValue: NewsItem[] | null;
modelValue: MpDraftApi.NewsItem[] | null;
}>();
const emit = defineEmits<{
(e: 'update:modelValue', v: NewsItem[]): void;
(e: 'update:modelValue', v: MpDraftApi.NewsItem[]): void;
}>();
// TODO @hw: 对齐 antd应该是 MpDraftApi.NewsItem 这种哈。
const newsList = computed<NewsItem[]>({
const newsList = computed<MpDraftApi.NewsItem[]>({
get() {
return props.modelValue === null
? [createEmptyNewsItem()]
@@ -124,7 +123,7 @@ function plusNews() {
size="small"
@click="() => moveDownNews(index)"
>
<IconifyIcon icon="ep:arrow-down-bold" />
<IconifyIcon icon="lucide:arrow-down" />
</ElButton>
<ElButton
v-if="isCreating"
@@ -133,7 +132,7 @@ function plusNews() {
size="small"
@click="() => removeNews(index)"
>
<IconifyIcon icon="ep:delete" />
<IconifyIcon icon="lucide:trash-2" />
</ElButton>
</div>
</div>
@@ -168,7 +167,7 @@ function plusNews() {
size="small"
@click="() => moveDownNews(index)"
>
<IconifyIcon icon="ep:arrow-down-bold" />
<IconifyIcon icon="lucide:arrow-down" />
</ElButton>
<ElButton
v-if="index > 0"
@@ -177,7 +176,7 @@ function plusNews() {
size="small"
@click="() => moveUpNews(index)"
>
<IconifyIcon icon="ep:arrow-up-bold" />
<IconifyIcon icon="lucide:arrow-up" />
</ElButton>
<ElButton
v-if="isCreating"
@@ -186,7 +185,7 @@ function plusNews() {
circle
@click="() => removeNews(index)"
>
<IconifyIcon icon="ep:delete" />
<IconifyIcon icon="lucide:trash-2" />
</ElButton>
</div>
</div>
@@ -201,7 +200,7 @@ function plusNews() {
@click="plusNews"
v-if="newsList.length < 8 && isCreating"
>
<IconifyIcon icon="ep:plus" />
<IconifyIcon icon="lucide:plus" />
</ElButton>
</ElRow>
</div>

View File

@@ -1,42 +0,0 @@
// TODO @hw合并到 api 里,参考 antd 的做法;
interface NewsItem {
title: string;
thumbMediaId: string;
author: string;
digest: string;
showCoverPic: number;
content: string;
contentSourceUrl: string;
needOpenComment: number;
onlyFansCanComment: number;
thumbUrl: string;
picUrl?: string; // 用于预览封面
}
interface NewsItemList {
newsItem: NewsItem[];
}
interface Article {
mediaId: string;
content: NewsItemList;
updateTime: number;
}
const createEmptyNewsItem = (): NewsItem => {
return {
title: '',
thumbMediaId: '',
author: '',
digest: '',
showCoverPic: 0,
content: '',
contentSourceUrl: '',
needOpenComment: 0,
onlyFansCanComment: 0,
thumbUrl: '',
};
};
export type { Article, NewsItem, NewsItemList };
export { createEmptyNewsItem };