Files
geo/apps/admin-web/src/views/KolGenerateView.vue
T

214 lines
5.0 KiB
Vue
Raw Normal View History

2026-04-17 14:59:52 +08:00
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { useMutation, useQuery } from "@tanstack/vue-query";
import { message } from "ant-design-vue";
import { ArrowLeftOutlined, ThunderboltOutlined } from "@ant-design/icons-vue";
import { kolGenerateApi } from "@/lib/api";
import KolDynamicForm from "@/components/kol/KolDynamicForm.vue";
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const subscriptionPromptId = computed(() => String(route.params.subscriptionPromptId));
const schemaQuery = useQuery({
queryKey: ["kol", "subscription-prompt", "schema", subscriptionPromptId],
queryFn: () => kolGenerateApi.schema(subscriptionPromptId.value),
enabled: computed(() => !!subscriptionPromptId.value),
});
const values = ref<Record<string, any>>({});
function fieldKey(key?: string | null, id?: string): string {
return key?.trim() || id || "";
}
2026-04-17 14:59:52 +08:00
// Initialize values from schema
watch(
() => schemaQuery.data.value,
(schema) => {
if (schema?.schema_json?.variables) {
const newValues: Record<string, any> = {};
schema.schema_json.variables.forEach((v) => {
newValues[fieldKey(v.key, v.id)] = v.type === "checkbox" ? [] : undefined;
2026-04-17 14:59:52 +08:00
});
values.value = newValues;
}
},
{ immediate: true }
);
const generateMutation = useMutation({
mutationFn: (variables: Record<string, any>) =>
kolGenerateApi.submit(subscriptionPromptId.value, { variables }),
onSuccess: (data) => {
message.success(t("common.copySuccess")); // Or a generic success message
void router.push({ name: "article-editor", params: { id: String(data.article_id) } });
},
onError: (error: any) => {
message.error(error.message || t("common.noData"));
},
});
function handleBack() {
router.back();
}
function handleSubmit() {
const schema = schemaQuery.data.value;
if (!schema?.schema_json?.variables) return;
const missingLabels: string[] = [];
schema.schema_json.variables.forEach((v) => {
if (v.required && !values.value[fieldKey(v.key, v.id)]) {
2026-04-17 14:59:52 +08:00
missingLabels.push(v.label);
}
});
if (missingLabels.length > 0) {
message.warning(`${t("kol.generate.fillVariables")}: ${missingLabels.join(", ")}`);
return;
}
generateMutation.mutate(values.value);
}
const schema = computed(() => schemaQuery.data.value);
</script>
<template>
<div class="kol-generate-view">
<div class="view-header">
<a-button type="link" @click="handleBack" class="back-btn">
<template #icon><ArrowLeftOutlined /></template>
{{ t("common.back") }}
</a-button>
</div>
<div v-if="schemaQuery.isPending.value" class="loading-state">
<a-spin size="large" />
</div>
<div v-else-if="schema" class="view-content">
<a-row :gutter="24" justify="center">
<a-col :xs="24" :lg="16" :xl="12">
<a-card class="generate-card">
<template #title>
<div class="card-header">
<span class="package-name">{{ schema.package_name }}</span>
<span class="divider">/</span>
<span class="prompt-name">{{ schema.prompt_name }}</span>
<a-tag v-if="schema.platform_hint" color="cyan" class="platform-badge">
{{ schema.platform_hint }}
</a-tag>
</div>
</template>
<div class="hint-text">
<ThunderboltOutlined class="hint-icon" />
{{ t("kol.generate.fillVariables") }}
</div>
<KolDynamicForm
v-model="values"
:variables="schema.schema_json.variables"
class="form-body"
/>
<div class="form-actions">
<a-button
type="primary"
size="large"
block
:loading="generateMutation.isPending.value"
@click="handleSubmit"
>
{{ t("kol.generate.submit") }}
</a-button>
</div>
</a-card>
</a-col>
</a-row>
</div>
</div>
</template>
<style scoped>
.kol-generate-view {
padding: 0;
}
.view-header {
margin-bottom: 16px;
}
.back-btn {
padding: 0;
color: #595959;
}
.loading-state {
display: flex;
justify-content: center;
padding: 100px;
}
.generate-card {
border-radius: 12px;
border: 1px solid #e6edf5;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
}
.card-header {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.package-name {
color: #8c8c8c;
font-weight: 400;
}
.divider {
color: #d9d9d9;
}
.prompt-name {
color: #1a1a1a;
font-weight: 600;
}
.platform-badge {
margin-left: 4px;
}
.hint-text {
margin-bottom: 24px;
padding: 12px 16px;
background: #f0f7ff;
border-radius: 8px;
color: #003a8c;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
}
.hint-icon {
color: #1890ff;
}
.form-body {
margin-bottom: 24px;
}
.form-actions {
margin-top: 32px;
}
</style>