feat(aigc): add video save support and improve consent flow

- add support for saving both image and video AIGC generation results
- refactor ResultActions component to accept mediaType prop and use dynamic save button text
- remove AIGC consent dialog from ChatQuickAccess and implement it on AIGC home page
- add WeChat mini-program privacy authorization check before saving media
- create reusable AigcConsentDialog component with proper styling
This commit is contained in:
duanshuwen
2026-07-16 21:49:00 +08:00
parent 38dbf7afc8
commit 52b6722842
6 changed files with 188 additions and 66 deletions

View File

@@ -1,133 +0,0 @@
<template>
<uni-popup
ref="popupRef"
type="center"
background-color="transparent"
mask-background-color="rgba(0, 0, 0, 0.58)"
:safe-area="false"
:is-mask-click="false"
@change="handlePopupChange"
>
<view
class="aigc-consent-overlay"
@touchmove.stop.prevent
>
<view class="aigc-consent-dialog">
<text class="aigc-consent-title">温馨提示</text>
<view class="aigc-consent-content">
<text v-if="content">{{ content }}</text>
<template v-else>
<text>{{ defaultContentPrefix }}</text>
<text class="aigc-consent-rule" @tap.stop="handleRuleClick">
{{ ruleName }}
</text>
<text>{{ defaultContentSuffix }}</text>
</template>
</view>
<view class="aigc-consent-actions">
<button
class="aigc-consent-button aigc-consent-cancel"
type="default"
@tap.stop="handleCancel"
>
取消
</button>
<button
class="aigc-consent-button aigc-consent-agree"
type="default"
@tap.stop="handleAgree"
>
我同意
</button>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { computed, nextTick, onMounted, ref, watch } from "vue";
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
companyName: {
type: String,
default: "智念科技服务有限公司",
},
ruleName: {
type: String,
default: "智念AI用户规则",
},
content: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:visible", "cancel", "agree", "ruleClick"]);
const popupRef = ref(null);
const defaultContentPrefix = computed(
() =>
`欢迎使用【${props.companyName}】提供的AI内容升级服务。本服务通过人工智能技术AIGC将您上传的照片或视频与景区场景模板进行创意优化为您生成具有特定风格的旅行内容。请您仔细阅读`
);
const defaultContentSuffix =
",您点击“我同意”等进行下一步操作的行为均视为您同意受本规则约束。如您不同意,您可以直接关闭页面。";
const close = () => {
popupRef.value?.close();
emit("update:visible", false);
};
const handleCancel = () => {
close();
emit("cancel");
};
const handleAgree = () => {
close();
emit("agree");
};
const handleRuleClick = () => {
emit("ruleClick");
};
const syncPopupVisible = async (visible) => {
await nextTick();
if (visible) {
popupRef.value?.open();
} else {
popupRef.value?.close();
}
};
const handlePopupChange = (event) => {
const show = event?.show ?? event?.detail?.show;
if (show === false && props.visible) {
emit("update:visible", false);
}
};
watch(
() => props.visible,
(visible) => {
syncPopupVisible(visible);
},
{ immediate: true }
);
onMounted(() => {
syncPopupVisible(props.visible);
});
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -1,75 +0,0 @@
.aigc-consent-overlay {
width: 100vw;
padding: 0 28px;
box-sizing: border-box;
}
.aigc-consent-dialog {
width: 100%;
padding: 34px 28px 26px;
border-radius: 24px;
background: #ffffff;
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.26);
box-sizing: border-box;
}
.aigc-consent-title {
display: block;
margin-bottom: 24px;
color: #111827;
font-size: 19px;
line-height: 26px;
font-weight: 900;
text-align: center;
}
.aigc-consent-content {
color: #606776;
font-size: 14px;
line-height: 25px;
font-weight: 700;
text-align: justify;
}
.aigc-consent-rule {
color: #18bd78;
font-weight: 900;
}
.aigc-consent-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin-top: 28px;
}
.aigc-consent-button {
width: 100%;
height: 54px;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
border-radius: 999px;
font-size: 16px;
line-height: 22px;
font-weight: 900;
box-sizing: border-box;
}
.aigc-consent-button::after {
border: 0;
}
.aigc-consent-cancel {
border: 1px solid #e2e6ea;
background: #ffffff;
color: #172033;
}
.aigc-consent-agree {
border: 1px solid #061c31;
background: #061c31;
color: #ffffff;
}

View File

@@ -11,8 +11,6 @@
</view>
</view>
</view>
<AigcConsentDialog v-model:visible="aigcConsentVisible" @agree="handleAigcConsentAgree" />
</view>
</template>
@@ -20,12 +18,9 @@
import { ref } from "vue";
import { Command } from "@/model/ChatModel";
import { SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
import { getAigcConsentAgreed, setAigcConsentAgreed } from "@/constant/aigc";
import { checkToken } from "@/hooks/useGoLogin";
import AigcConsentDialog from "../AigcConsentDialog/index.vue";
const AIGC_HOME_URL = "/pages-aigc/home/home";
const aigcConsentVisible = ref(false);
const itemList = ref([
{
@@ -81,11 +76,7 @@ const sendReply = (item) => {
// 旅行AIGC
if (item.type === Command.travelAIGC) {
checkToken().then(() => {
if (getAigcConsentAgreed()) {
navigateToAigcHome();
} else {
aigcConsentVisible.value = true;
}
navigateToAigcHome();
});
return;
}
@@ -96,11 +87,6 @@ const sendReply = (item) => {
const navigateToAigcHome = () => {
uni.navigateTo({ url: AIGC_HOME_URL });
};
const handleAigcConsentAgree = () => {
setAigcConsentAgreed(true);
navigateToAigcHome();
};
</script>
<style lang="scss" scoped>