2026-02-03 13:15:39 +08:00
|
|
|
<template>
|
2026-02-10 13:05:24 +08:00
|
|
|
<div class="assist-input-wrapper flex flex-col" :class="{ agent: isAgentMode }">
|
2026-03-05 11:46:41 +08:00
|
|
|
<div class="animate-container flex-1 flex flex-col">
|
|
|
|
|
<div class="scroll-content flex-col">
|
2026-04-30 14:18:19 +08:00
|
|
|
<InputImagePreviewList
|
|
|
|
|
:uploaded-images="uploadedImages"
|
|
|
|
|
:quote-list="quoteList"
|
|
|
|
|
@preview="previewImage"
|
|
|
|
|
@remove="removeImage"
|
|
|
|
|
/>
|
|
|
|
|
<InputEditor
|
|
|
|
|
:show-placeholder="showPlaceholder"
|
|
|
|
|
:placeholder="$t('Input.placeholder')"
|
|
|
|
|
:is-agent-mode="isAgentMode"
|
|
|
|
|
@ready="setEditorElement"
|
|
|
|
|
@input="handleEditorInput"
|
|
|
|
|
@paste="handleEditorPaste"
|
|
|
|
|
@keydown="handleKeyDown"
|
|
|
|
|
/>
|
2026-02-10 13:05:24 +08:00
|
|
|
</div>
|
2026-03-05 11:46:41 +08:00
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
<InputToolbar
|
|
|
|
|
v-model:type-value="typeValue"
|
|
|
|
|
v-model:area-value="areaValue"
|
|
|
|
|
v-model:style-value="styleValue"
|
|
|
|
|
v-model:setting-options="settingOptions"
|
|
|
|
|
:is-agent-mode="isAgentMode"
|
|
|
|
|
:generating="generating"
|
|
|
|
|
:type-options="typeOptions"
|
|
|
|
|
:area-options="areaOptions"
|
|
|
|
|
:style-options="styleOptions"
|
|
|
|
|
:type-placeholder="$t('Input.typePlaceholder')"
|
|
|
|
|
:area-placeholder="$t('Input.areaPlaceholder')"
|
|
|
|
|
:style-placeholder="$t('Input.stylePlaceholder')"
|
|
|
|
|
:style-title="$t('Input.chooseStyle')"
|
|
|
|
|
:setting-title="$t('Input.styleTitle')"
|
|
|
|
|
:confirm-text="$t('Input.confirm')"
|
|
|
|
|
:create-text="$t('Input.createProject')"
|
2026-05-04 09:41:58 +08:00
|
|
|
:parameters-disabled="isReportSelected"
|
2026-04-30 14:18:19 +08:00
|
|
|
:translate="translate"
|
|
|
|
|
@file-change="handleFileChange"
|
2026-05-04 09:41:58 +08:00
|
|
|
@toggle-report="handleToggleReportTag"
|
2026-04-30 14:18:19 +08:00
|
|
|
@create="handleCreateProject"
|
|
|
|
|
@send="handleSendAgent"
|
|
|
|
|
/>
|
2026-02-10 13:05:24 +08:00
|
|
|
</div>
|
2026-03-05 11:46:41 +08:00
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
<ReportShortcutButton
|
2026-03-09 10:56:38 +08:00
|
|
|
v-if="!isAgentMode"
|
2026-04-30 14:18:19 +08:00
|
|
|
:is-cn="isCn"
|
|
|
|
|
:label="$t('Input.trendingReport')"
|
2026-05-04 09:41:58 +08:00
|
|
|
@click="handleToggleReportTag"
|
2026-04-30 14:18:19 +08:00
|
|
|
/>
|
2026-03-09 14:02:07 +08:00
|
|
|
<Preview v-model="showPreview" :url="previewUrl" />
|
2026-02-10 13:05:24 +08:00
|
|
|
</div>
|
2026-02-03 13:15:39 +08:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-04-30 14:18:19 +08:00
|
|
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
2026-02-10 13:05:24 +08:00
|
|
|
import { areaList } from '@/utils/area'
|
|
|
|
|
import { useI18n } from 'vue-i18n'
|
2026-02-24 13:53:01 +08:00
|
|
|
import { useRouter } from 'vue-router'
|
2026-02-25 11:00:31 +08:00
|
|
|
import { useAgentStore, useProjectStore } from '@/stores'
|
|
|
|
|
import { createProject } from '@/api/agent'
|
2026-03-02 14:03:59 +08:00
|
|
|
import MyEvent from '@/utils/myEvent'
|
2026-03-09 13:36:11 +08:00
|
|
|
import Preview from '@/components/Preview/Preview.vue'
|
2026-04-30 14:18:19 +08:00
|
|
|
import InputEditor from './input/InputEditor.vue'
|
|
|
|
|
import InputImagePreviewList from './input/InputImagePreviewList.vue'
|
|
|
|
|
import InputToolbar from './input/InputToolbar.vue'
|
|
|
|
|
import ReportShortcutButton from './input/ReportShortcutButton.vue'
|
|
|
|
|
import {
|
|
|
|
|
createSettingOptions,
|
|
|
|
|
createStyleOptions,
|
|
|
|
|
createTypeOptions
|
|
|
|
|
} from './input/options'
|
|
|
|
|
import { useInputEditor } from './input/useInputEditor'
|
|
|
|
|
import { useInputImages } from './input/useInputImages'
|
|
|
|
|
import type { OptionItem, SettingOption } from './input/types'
|
2026-02-10 13:05:24 +08:00
|
|
|
|
2026-02-24 13:53:01 +08:00
|
|
|
const router = useRouter()
|
|
|
|
|
const agentStore = useAgentStore()
|
2026-02-25 11:00:31 +08:00
|
|
|
const projectStore = useProjectStore()
|
2026-02-24 13:53:01 +08:00
|
|
|
|
2026-02-10 13:05:24 +08:00
|
|
|
const props = withDefaults(
|
|
|
|
|
defineProps<{
|
|
|
|
|
isAgentMode?: boolean
|
2026-02-25 11:00:31 +08:00
|
|
|
generating?: boolean
|
2026-02-10 13:05:24 +08:00
|
|
|
}>(),
|
|
|
|
|
{
|
2026-02-25 11:00:31 +08:00
|
|
|
isAgentMode: false,
|
|
|
|
|
generating: false
|
2026-02-10 13:05:24 +08:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2026-02-25 11:00:31 +08:00
|
|
|
const emits = defineEmits(['send', 'pause'])
|
2026-02-10 13:05:24 +08:00
|
|
|
|
2026-03-24 16:57:40 +08:00
|
|
|
const { t, locale } = useI18n()
|
2026-04-30 14:18:19 +08:00
|
|
|
const translate = (key: string) => t(key)
|
2026-03-24 16:57:40 +08:00
|
|
|
|
|
|
|
|
const isCn = computed(() => {
|
|
|
|
|
return locale.value === 'CHINESE_SIMPLIFIED'
|
|
|
|
|
})
|
2026-04-30 14:18:19 +08:00
|
|
|
const isAgentModeRef = computed(() => props.isAgentMode)
|
2026-02-10 13:05:24 +08:00
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
const typeValue = ref<string>('')
|
|
|
|
|
const areaValue = ref<string>('')
|
|
|
|
|
const styleValue = ref<string>('')
|
|
|
|
|
const settingOptions = ref<SettingOption[]>(createSettingOptions())
|
|
|
|
|
const typeOptions = ref<OptionItem[]>(createTypeOptions())
|
|
|
|
|
const areaOptions = ref<OptionItem[]>(areaList)
|
|
|
|
|
const styleOptions = ref<OptionItem[]>(createStyleOptions())
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
inputValue,
|
|
|
|
|
reportTags,
|
|
|
|
|
showPlaceholder,
|
|
|
|
|
setEditorElement,
|
|
|
|
|
focusEditor,
|
|
|
|
|
stopReportTypewriter,
|
|
|
|
|
addReportTag,
|
|
|
|
|
toggleReportTag,
|
|
|
|
|
handleEditorInput,
|
|
|
|
|
handleEditorPaste,
|
|
|
|
|
handleKeyDown,
|
|
|
|
|
autoResizeEditor,
|
|
|
|
|
syncOptionTag,
|
|
|
|
|
syncAllOptionTags,
|
|
|
|
|
clearEditorText,
|
|
|
|
|
resetOptionTags
|
|
|
|
|
} = useInputEditor({
|
|
|
|
|
isAgentMode: isAgentModeRef,
|
|
|
|
|
t: translate,
|
|
|
|
|
typeValue,
|
|
|
|
|
areaValue,
|
|
|
|
|
styleValue,
|
|
|
|
|
typeOptions,
|
|
|
|
|
areaOptions,
|
|
|
|
|
styleOptions,
|
|
|
|
|
onSubmit: () => {
|
2026-02-26 16:48:08 +08:00
|
|
|
if (props.isAgentMode) {
|
|
|
|
|
handleSendAgent()
|
2026-04-30 14:18:19 +08:00
|
|
|
return
|
2026-02-23 14:53:29 +08:00
|
|
|
}
|
2026-04-30 14:18:19 +08:00
|
|
|
handleCreateProject()
|
2026-02-11 16:32:38 +08:00
|
|
|
}
|
2026-04-30 14:18:19 +08:00
|
|
|
})
|
2026-02-11 16:32:38 +08:00
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
const {
|
|
|
|
|
uploadedImages,
|
|
|
|
|
quoteList,
|
|
|
|
|
showPreview,
|
|
|
|
|
previewUrl,
|
|
|
|
|
handleFileChange,
|
|
|
|
|
removeImage,
|
|
|
|
|
previewImage,
|
|
|
|
|
handleQuote,
|
|
|
|
|
clearImages
|
|
|
|
|
} = useInputImages(focusEditor)
|
2026-02-26 16:48:08 +08:00
|
|
|
|
2026-05-04 09:41:58 +08:00
|
|
|
const isReportSelected = computed(() => {
|
|
|
|
|
return reportTags.value.some((tag) => tag.parentNode)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const clearParameterValues = () => {
|
|
|
|
|
typeValue.value = ''
|
|
|
|
|
areaValue.value = ''
|
|
|
|
|
styleValue.value = ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleToggleReportTag = () => {
|
|
|
|
|
const shouldSelectReport = !isReportSelected.value
|
|
|
|
|
toggleReportTag()
|
|
|
|
|
if (shouldSelectReport) {
|
|
|
|
|
clearParameterValues()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-10 13:05:24 +08:00
|
|
|
watch(inputValue, () => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
autoResizeEditor()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-30 13:57:41 +08:00
|
|
|
watch(typeValue, () => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
syncOptionTag('type')
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
watch(areaValue, () => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
syncOptionTag('area')
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
watch(styleValue, () => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
syncOptionTag('style')
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
watch(locale, () => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
syncAllOptionTags()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
const handleSendAgent = async () => {
|
|
|
|
|
if (props.generating) {
|
|
|
|
|
emits('pause')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!inputValue.value.trim()) return
|
|
|
|
|
const imageUrlList = uploadedImages.value.map((item) => item.path)
|
|
|
|
|
|
|
|
|
|
const payload: {
|
|
|
|
|
text: string
|
|
|
|
|
images: any[]
|
|
|
|
|
tempImages: typeof uploadedImages.value
|
|
|
|
|
quoteList: string[]
|
|
|
|
|
useReport?: boolean
|
|
|
|
|
} = {
|
|
|
|
|
text: inputValue.value.trim(),
|
|
|
|
|
images: imageUrlList,
|
|
|
|
|
tempImages: uploadedImages.value,
|
|
|
|
|
quoteList: quoteList.value
|
|
|
|
|
}
|
|
|
|
|
if (reportTags.value.length > 0) {
|
|
|
|
|
payload.useReport = true
|
|
|
|
|
}
|
|
|
|
|
emits('send', payload)
|
|
|
|
|
clearImages()
|
|
|
|
|
clearEditorText()
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-25 11:00:31 +08:00
|
|
|
const handleCreateProject = async () => {
|
2026-03-02 16:40:40 +08:00
|
|
|
if (!inputValue.value.trim()) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-10 16:28:11 +08:00
|
|
|
|
2026-02-24 13:53:01 +08:00
|
|
|
const params = {
|
2026-04-10 15:54:13 +08:00
|
|
|
type: typeValue.value || '',
|
|
|
|
|
area: areaValue.value || '',
|
|
|
|
|
style: styleValue.value || '',
|
2026-03-10 16:28:11 +08:00
|
|
|
useReport: reportTags.value.length > 0,
|
2026-02-25 11:00:31 +08:00
|
|
|
temperature: 0.7
|
2026-02-24 13:53:01 +08:00
|
|
|
}
|
2026-04-30 14:18:19 +08:00
|
|
|
const projectres = await createProject({
|
|
|
|
|
...params,
|
|
|
|
|
region: params.area
|
|
|
|
|
} as any)
|
2026-02-25 11:00:31 +08:00
|
|
|
projectStore.setId(projectres)
|
2026-03-02 14:03:59 +08:00
|
|
|
MyEvent.emit('updateProjectList')
|
2026-02-24 13:53:01 +08:00
|
|
|
agentStore.setInitialProjectData({
|
|
|
|
|
text: inputValue.value.trim(),
|
2026-03-02 15:08:03 +08:00
|
|
|
images: uploadedImages.value.map((item) => item.path),
|
|
|
|
|
tempImages: uploadedImages.value,
|
2026-04-30 14:18:19 +08:00
|
|
|
needSuggestion: false,
|
|
|
|
|
quoteList: quoteList.value,
|
2026-02-25 11:00:31 +08:00
|
|
|
...params
|
2026-02-24 13:53:01 +08:00
|
|
|
})
|
|
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
router.push({
|
|
|
|
|
path: `/home/agent/${projectres}`,
|
|
|
|
|
query: {
|
|
|
|
|
type: params.type,
|
|
|
|
|
area: params.area,
|
|
|
|
|
style: params.style,
|
|
|
|
|
useReport: String(params.useReport),
|
|
|
|
|
temperature: String(params.temperature)
|
|
|
|
|
}
|
|
|
|
|
})
|
2026-03-02 15:08:03 +08:00
|
|
|
uploadedImages.value = []
|
2026-02-24 13:53:01 +08:00
|
|
|
}
|
2026-02-26 16:48:08 +08:00
|
|
|
|
2026-03-27 11:45:06 +08:00
|
|
|
const handleInitInput = () => {
|
|
|
|
|
inputValue.value = ''
|
|
|
|
|
uploadedImages.value = []
|
|
|
|
|
quoteList.value = []
|
2026-04-30 14:18:19 +08:00
|
|
|
toggleReportTag(true)
|
|
|
|
|
clearEditorText()
|
|
|
|
|
resetOptionTags()
|
2026-04-30 13:57:41 +08:00
|
|
|
nextTick(() => {
|
|
|
|
|
syncAllOptionTags()
|
|
|
|
|
})
|
2026-03-27 11:45:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
MyEvent.add('quote', handleQuote)
|
|
|
|
|
MyEvent.add('projectChange', handleInitInput)
|
|
|
|
|
nextTick(() => {
|
2026-04-30 13:57:41 +08:00
|
|
|
syncAllOptionTags()
|
2026-03-27 11:45:06 +08:00
|
|
|
autoResizeEditor()
|
|
|
|
|
})
|
|
|
|
|
})
|
2026-04-30 14:18:19 +08:00
|
|
|
|
2026-03-24 16:57:40 +08:00
|
|
|
onUnmounted(() => {
|
2026-04-30 10:11:19 +08:00
|
|
|
stopReportTypewriter()
|
2026-03-24 16:57:40 +08:00
|
|
|
MyEvent.remove('quote', handleQuote)
|
2026-03-27 11:45:06 +08:00
|
|
|
MyEvent.remove('projectChange', handleInitInput)
|
2026-03-24 16:57:40 +08:00
|
|
|
})
|
2026-04-30 14:18:19 +08:00
|
|
|
|
2026-02-26 16:48:08 +08:00
|
|
|
defineExpose({
|
|
|
|
|
addReportTag
|
|
|
|
|
})
|
2026-02-03 13:15:39 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
2026-02-10 13:05:24 +08:00
|
|
|
.assist-input-wrapper {
|
|
|
|
|
min-height: 23.5rem;
|
|
|
|
|
max-height: 43.5rem;
|
|
|
|
|
width: 106.3rem;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 0;
|
|
|
|
|
position: relative;
|
2026-04-30 14:18:19 +08:00
|
|
|
|
2026-03-06 13:26:14 +08:00
|
|
|
.animate-container {
|
|
|
|
|
overflow-y: hidden;
|
|
|
|
|
}
|
2026-02-10 13:05:24 +08:00
|
|
|
|
2026-03-05 11:46:41 +08:00
|
|
|
&:not(.agent) .animate-container {
|
|
|
|
|
box-shadow: 0px 0.5rem 1.4rem 0px #0000001a;
|
2026-03-04 15:27:56 +08:00
|
|
|
transition: all 0.3s ease;
|
2026-03-05 11:46:41 +08:00
|
|
|
border-radius: 2.8rem;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
border: 0.1rem solid #00000005;
|
2026-04-30 14:18:19 +08:00
|
|
|
|
|
|
|
|
&:hover {
|
2026-03-05 11:46:41 +08:00
|
|
|
box-shadow: 0px 0.5rem 3.36rem 2.2rem #f1ede999;
|
|
|
|
|
transform: translateY(-1rem);
|
2026-02-10 13:05:24 +08:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-30 14:18:19 +08:00
|
|
|
|
2026-02-10 13:05:24 +08:00
|
|
|
.scroll-content {
|
2026-02-24 11:17:01 +08:00
|
|
|
display: flex;
|
2026-03-09 10:36:43 +08:00
|
|
|
flex-direction: column;
|
2026-02-23 14:53:29 +08:00
|
|
|
flex: 1;
|
|
|
|
|
overflow-y: auto;
|
2026-02-10 13:05:24 +08:00
|
|
|
padding: 3.4rem 1.7rem 1.7rem;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
&.agent {
|
|
|
|
|
padding: 1.2rem;
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
border-radius: 1.5rem;
|
|
|
|
|
border: 0.1rem solid #0000001a;
|
2026-02-10 13:05:24 +08:00
|
|
|
|
2026-04-30 14:18:19 +08:00
|
|
|
.scroll-content {
|
2026-03-09 14:44:30 +08:00
|
|
|
padding: 0;
|
2026-02-10 13:05:24 +08:00
|
|
|
flex: 1;
|
2026-04-30 14:18:19 +08:00
|
|
|
overflow: auto;
|
2026-03-17 14:16:14 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-03 15:46:05 +08:00
|
|
|
</style>
|