feat(media-supply): add media resource supply marketplace
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m49s
Backend CI / Backend (push) Failing after 7m10s
Desktop Client Build / Build Desktop Client (push) Successful in 23m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m49s
Backend CI / Backend (push) Failing after 7m10s
Desktop Client Build / Build Desktop Client (push) Successful in 23m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
Introduce an end-to-end media-supply feature: tenant-side resource sync service/worker backed by a Meijiequan supplier client, ops-side management APIs, and admin/ops web views for resources, orders, favorites and submission. Adds a shared digitocr helper, MediaSupply config blocks for tenant and ops, shared types, and migrations for supplier media resources, price overrides, customer visibility and order refunds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -108,14 +108,19 @@ import {
|
||||
type RichImageAlign,
|
||||
} from '@/lib/milkdown/richImageBlock'
|
||||
|
||||
const props = defineProps<{
|
||||
articleId: number
|
||||
const props = withDefaults(defineProps<{
|
||||
articleId?: number | null
|
||||
title: string
|
||||
modelValue: string
|
||||
disabled?: boolean
|
||||
toolbar?: boolean
|
||||
aiOptimizeEnabled?: boolean
|
||||
complianceViolations?: ComplianceViolation[]
|
||||
uploadImage?: (file: File) => Promise<string>
|
||||
}>()
|
||||
}>(), {
|
||||
toolbar: true,
|
||||
aiOptimizeEnabled: true,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:title': [value: string]
|
||||
@@ -532,6 +537,9 @@ function createCrepe(root: HTMLElement): Crepe {
|
||||
featureConfigs: {
|
||||
[CrepeFeature.Toolbar]: {
|
||||
buildToolbar: (builder) => {
|
||||
if (!canUseAiOptimize.value) {
|
||||
return
|
||||
}
|
||||
builder.addGroup('ai-optimize', 'AI Optimize').addItem('ai-optimize', {
|
||||
icon: AI_OPTIMIZE_TOOLBAR_ICON,
|
||||
active: () => false,
|
||||
@@ -604,6 +612,13 @@ let aiOptimizeIgnoreNextWindowPointerDown = false
|
||||
const EDITOR_ACTION_MENU_DROPDOWN_SELECTOR = '.editor-action-menu__dropdown-overlay'
|
||||
|
||||
const tableContextHeaderRow = computed(() => tableContextMenu.value.rowIndex === 0)
|
||||
const showEditorToolbar = computed(() => props.toolbar !== false)
|
||||
const canUseAiOptimize = computed(
|
||||
() =>
|
||||
props.aiOptimizeEnabled !== false &&
|
||||
Number.isInteger(props.articleId) &&
|
||||
Number(props.articleId) > 0,
|
||||
)
|
||||
const aiOptimizeStreaming = computed(() => aiOptimizeStatus.value === 'generating')
|
||||
const aiOptimizeHasPreview = computed(() => aiOptimizePreview.value.trim().length > 0)
|
||||
const aiOptimizeUiText = computed(() => ({
|
||||
@@ -1354,7 +1369,7 @@ function resolveAiOptimizePanelFrame(anchorRect: DOMRect): {
|
||||
}
|
||||
|
||||
function openAiOptimizePanel(ctx: Ctx): void {
|
||||
if (editorDisabled.value) {
|
||||
if (editorDisabled.value || !canUseAiOptimize.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1434,7 +1449,7 @@ function handleAiOptimizeStreamEvent(event: ArticleSelectionOptimizeStreamEvent)
|
||||
}
|
||||
|
||||
async function generateAiOptimizePreview(): Promise<void> {
|
||||
if (!aiOptimizePanel.value.open || editorDisabled.value) {
|
||||
if (!canUseAiOptimize.value || !aiOptimizePanel.value.open || editorDisabled.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1454,7 +1469,7 @@ async function generateAiOptimizePreview(): Promise<void> {
|
||||
|
||||
try {
|
||||
await streamArticleSelectionOptimize(
|
||||
props.articleId,
|
||||
Number(props.articleId),
|
||||
{
|
||||
title: props.title,
|
||||
markdown_content: props.modelValue,
|
||||
@@ -2259,7 +2274,7 @@ function runTableContextAction(action: TableContextMenuAction): void {
|
||||
'article-editor-canvas--ai-optimize-open': aiOptimizePanel.open,
|
||||
}"
|
||||
>
|
||||
<div class="article-editor-canvas__toolbar">
|
||||
<div v-if="showEditorToolbar" class="article-editor-canvas__toolbar">
|
||||
<a-button size="small" type="text" @click="runCommand(undoCommand)">
|
||||
<template #icon><IconFont type="icon-Undo" /></template>
|
||||
</a-button>
|
||||
@@ -2385,7 +2400,7 @@ function runTableContextAction(action: TableContextMenuAction): void {
|
||||
/>
|
||||
|
||||
<EditorAiAssistPanel
|
||||
v-if="aiOptimizePanel.open"
|
||||
v-if="canUseAiOptimize && aiOptimizePanel.open"
|
||||
v-model:prompt="aiOptimizeInstruction"
|
||||
:x="aiOptimizePanel.x"
|
||||
:y="aiOptimizePanel.y"
|
||||
@@ -2417,7 +2432,7 @@ function runTableContextAction(action: TableContextMenuAction): void {
|
||||
|
||||
<CoverPickerModal
|
||||
v-model:open="imagePickerOpen"
|
||||
:article-id="articleId"
|
||||
:article-id="articleId ?? null"
|
||||
:platform-ids="[]"
|
||||
:current-url="imagePickerCurrentUrl"
|
||||
:current-asset-id="imagePickerCurrentAssetId"
|
||||
|
||||
Reference in New Issue
Block a user