Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<template>
<div class="ai-chat__operate p-16-24">
<slot name="operateBefore" />

<div class="operate-textarea">
<el-scrollbar max-height="136">
<div
Expand Down
36 changes: 25 additions & 11 deletions ui/src/components/ai-chat/component/user-form/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,16 @@
(inputFieldList.length > 0 || (type === 'debug-ai-chat' && apiInputFieldList.length > 0)) &&
type !== 'log'
"
class="mb-16"
style="padding: 0 24px"
class="mb-16 w-full"
style="padding: 0 24px; max-width: 400px"
>
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 16px 8px">
<div
class="flex align-center cursor w-full"
style="padding: 0 8px"
@click="showUserInput = !showUserInput"
>
<el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
<div class="flex align-center cursor w-full" style="padding: 0 8px">
<!-- <el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
><CaretRight
/></el-icon>
/></el-icon> -->
<span class="break-all ellipsis-1 mr-16" :title="inputFieldConfig.title">
{{ inputFieldConfig.title }}
{{ inputFieldConfig.title }}
</span>
</div>
<el-scrollbar max-height="160">
Expand All @@ -44,6 +40,15 @@
</div>
</el-collapse-transition>
</el-scrollbar>
<div class="text-right mr-8">
<el-button type="primary" v-if="first" @click="confirmHandle">{{
$t('chat.operation.startChat')
}}</el-button>
<el-button v-if="!first" @click="cancelHandle">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" v-if="!first" @click="confirmHandle">{{
$t('common.confirm')
}}</el-button>
</div>
</el-card>
</div>
</template>
Expand All @@ -60,14 +65,15 @@ const props = defineProps<{
type: 'log' | 'ai-chat' | 'debug-ai-chat'
api_form_data: any
form_data: any
first: boolean
}>()
// 用于刷新动态表单
const dynamicsFormRefresh = ref(0)
const inputFieldList = ref<FormField[]>([])
const apiInputFieldList = ref<FormField[]>([])
const inputFieldConfig = ref({ title: t('chat.userInput') })
const showUserInput = ref(true)
const emit = defineEmits(['update:api_form_data', 'update:form_data'])
const emit = defineEmits(['update:api_form_data', 'update:form_data', 'confirm', 'cancel'])

const api_form_data_context = computed({
get: () => {
Expand Down Expand Up @@ -324,6 +330,14 @@ const decodeQuery = (query: string) => {
return query
}
}
const confirmHandle = () => {
if (checkInputParam()) {
emit('confirm')
}
}
const cancelHandle = () => {
emit('cancel')
}
defineExpose({ checkInputParam })
onMounted(() => {
handleInputFieldList()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code snippet seems to be a template file for an El-Cli application using Vue.js and Element Plus. Here are some points to consider regarding irregularities, potential issues, and optimization suggestions:

Irregularities

  • Class Attribute Issue: The style attribute has both max-width set but no corresponding CSS rules applying it. This might result in unexpected behavior.

Potential Issues

  1. Uninitialized Variables:

    • It is not clear what dynamicsForm_refresh, inputFieldList, api_inputFieldList, inputFieldConfig, showUserInput mean based solely on this code.
  2. Code Duplication:

    • There is duplicate usage of the same button components with slightly different text (startChat, cancel) in two places within the card's footer.
  3. Function Handling:

    • While checkInputParam() function exists and is called conditionally, its logic isn't shown. Ensure that this function correctly checks input conditions before proceeding with confirmation/abort actions.
  4. Missing Event Handlers:

    • Although there are comments indicating event handling for confirmation/cancellation, they are not implemented in the defined emits at the bottom of the component script.
  5. Template Logic Flaws:

    • The visibility management for showUserInput seems unnecessary since the initial value (true) implies it should always be visible unless explicitly toggled elsewhere in the lifecycle hooks/functions.
  6. Dynamic Form Behavior:

    • The existence of handleInputFieldList suggests dynamic loading of form fields, yet there’s limited context about how this works or the purpose of dynamicFormRefresh.

Optimization Suggestions

  • Separation Concerns: Try separating styles and scripts from the HTML templating. Currently everything is mixed together, which can lead to bloated templates.

  • Consistent Button Text Usage: If startChat & confirm buttons appear multiple times without any significant difference between them, consolidate these into one with conditional labels like: <el-button>{{ first ? $t('chat.operation.startChat') : $t('common.confirm') }}</el-button>.

  • Refactor Code Organization: Consider organizing related variables/functions more clearly so that each part can have a specific and descriptive responsibility.

Here is improved version reflecting above considerations:

<template>
  <!-- ...existing template content -->
</template>

<script setup lang='ts'>
// Importing necessary modules...
import { defineProps, ref, computed, defineEmits } from 'vue';

interface FormField {
  title: string;
}

const props = defineProps<{
  type: 'log' | 'ai-chat' | 'debug-ai-chat';
  api_form_data: any;
  form_data: any;
  first: boolean;
}>();

const emit = defineEmits(['update:api_form_data', 'update:form_data']);

// ...methods...

const confirmHandle = () => {
  if (checkInputParam()) {
    emit('confirm');
  }
};

const cancelHandle = () => {
  emit('cancel');
};

defineExpose({ checkInputParam });
onMounted(() => handleInputFieldList());
</script>

<style scoped>
/* Existing styles... */
.arrow-icon,
.rotate-90 {
  /* Styles here... */
}
</style>

Ensure further adjustments according to project standards and actual requirements.

Expand Down
149 changes: 102 additions & 47 deletions ui/src/components/ai-chat/index.vue
Original file line number Diff line number Diff line change
@@ -1,56 +1,76 @@
<template>
<div ref="aiChatRef" class="ai-chat" :class="type">
<UserForm
v-model:api_form_data="api_form_data"
v-model:form_data="form_data"
:application="applicationDetails"
:type="type"
ref="userFormRef"
></UserForm>
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
<div ref="dialogScrollbar" class="ai-chat__content p-24">
<PrologueContent
:type="type"
:application="applicationDetails"
:available="available"
:send-message="sendMessage"
></PrologueContent>

<template v-for="(item, index) in chatList" :key="index">
<!-- 问题 -->
<QuestionContent
<div
v-show="(isUserInput && firsUserInput) || showUserInput"
:class="firsUserInput ? 'firstUserInput' : 'popperUserInput'"
>
<UserForm
v-model:api_form_data="api_form_data"
v-model:form_data="form_data"
:application="applicationDetails"
:type="type"
:first="firsUserInput"
@confirm="UserFormConfirm"
@cancel="() => (showUserInput = false)"
ref="userFormRef"
></UserForm>
</div>
<template v-if="!firsUserInput">
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
<div ref="dialogScrollbar" class="ai-chat__content p-24">
<PrologueContent
:type="type"
:application="applicationDetails"
:chat-record="item"
></QuestionContent>
<!-- 回答 -->
<AnswerContent
:application="applicationDetails"
:loading="loading"
v-model:chat-record="chatList[index]"
:type="type"
:available="available"
:send-message="sendMessage"
:chat-management="ChatManagement"
></AnswerContent>
></PrologueContent>

<template v-for="(item, index) in chatList" :key="index">
<!-- 问题 -->
<QuestionContent
:type="type"
:application="applicationDetails"
:chat-record="item"
></QuestionContent>
<!-- 回答 -->
<AnswerContent
:application="applicationDetails"
:loading="loading"
v-model:chat-record="chatList[index]"
:type="type"
:send-message="sendMessage"
:chat-management="ChatManagement"
></AnswerContent>
</template>
</div>
</el-scrollbar>

<ChatInputOperate
:app-id="appId"
:application-details="applicationDetails"
:is-mobile="isMobile"
:type="type"
:send-message="sendMessage"
:open-chat-id="openChatId"
:chat-management="ChatManagement"
v-model:chat-id="chartOpenId"
v-model:loading="loading"
v-if="type !== 'log'"
>
<template #operateBefore>
<div class="flex-between">
<slot name="operateBefore">
<span></span>
</slot>
<el-button class="user-input-button mb-8" type="primary" text @click="toggleUserInput">
<AppIcon iconName="app-user-input"></AppIcon>
</el-button>
</div>
</template>
</div>
</el-scrollbar>
</ChatInputOperate>

<ChatInputOperate
:app-id="appId"
:application-details="applicationDetails"
:is-mobile="isMobile"
:type="type"
:send-message="sendMessage"
:open-chat-id="openChatId"
:chat-management="ChatManagement"
v-model:chat-id="chartOpenId"
v-model:loading="loading"
v-if="type !== 'log'"
>
<template #operateBefore> <slot name="operateBefore" /> </template>
</ChatInputOperate>
<Control></Control>
<Control></Control>
</template>
</div>
</template>
<script setup lang="ts">
Expand All @@ -62,7 +82,7 @@ import { ChatManagement, type chatType } from '@/api/type/application'
import { randomId } from '@/utils/utils'
import useStore from '@/stores'
import { isWorkFlow } from '@/utils/application'
import { debounce } from 'lodash'
import { debounce, first } from 'lodash'
import AnswerContent from '@/components/ai-chat/component/answer-content/index.vue'
import QuestionContent from '@/components/ai-chat/component/question-content/index.vue'
import ChatInputOperate from '@/components/ai-chat/component/chat-input-operate/index.vue'
Expand Down Expand Up @@ -106,13 +126,25 @@ const chatList = ref<any[]>([])
const form_data = ref<any>({})
const api_form_data = ref<any>({})
const userFormRef = ref<InstanceType<typeof UserForm>>()
// 用户输入
const firsUserInput = ref(true)
const showUserInput = ref(false)

const isUserInput = computed(
() =>
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
.properties.user_input_field_list.length > 0
)

watch(
() => props.chatId,
(val) => {
if (val && val !== 'new') {
chartOpenId.value = val
firsUserInput.value = false
} else {
chartOpenId.value = ''
firsUserInput.value = true
}
},
{ deep: true }
Expand All @@ -136,6 +168,15 @@ watch(
}
)

const toggleUserInput = () => {
showUserInput.value = !showUserInput.value
}

function UserFormConfirm() {
firsUserInput.value = false
showUserInput.value = false
}

function sendMessage(val: string, other_params_data?: any, chat?: chatType) {
if (!userFormRef.value?.checkInputParam()) {
return
Expand Down Expand Up @@ -467,4 +508,18 @@ defineExpose({
</script>
<style lang="scss" scoped>
@import './index.scss';
.firstUserInput {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.popperUserInput {
position: absolute;
z-index: 999;
right: 50px;
bottom: 80px;
width: calc(100% - 50px);
max-width: 400px;
}
</style>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code you provided contains some improvements and optimizations over its initial version. Here's an overview of the changes:

  1. Modularized UI Components: The components (UserForm, PrologueContent, QuestionContent, etc.) are now encapsulated within individual Vue component files, improving modularity.

  2. Conditional Rendering:

    • Replaced manual handling of isUserInput logic with computed properties to improve readability.
    • Introduced a new variable showUserInput for toggling the user input section. This simplifies conditional rendering.
    • Added comments above each change to explain logical decisions.
  3. Debouncing Functions: Utilized lodash's debounce function for more efficient debounced functions.

  4. CSS Styles:

    • Added classes firstUserInput and popperUserInput for styling different states of the user input section, making it easier to target specific behaviors like popups or custom buttons.
  5. Refactoring Code Style:

    • Removed redundant code duplication and replaced it with loops and conditionals where appropriate.

Potential Improvements:

While these refinements enhance both usability and maintainability, there might be areas for further improvement depending on specific requirements such as performance tuning or additional functionality. For instance:

  • Performance Optimization: Ensure that any debounced functions are not excessively called or unnecessarily complex; they should aim to optimize responsiveness without affecting system performance heavily.
  • Validation Logic: Consider adding more robust validation checks before sending messages, especially if sensitive data is involved.
  • Accessibility Enhancements: Implement proper keyboard navigation and aria-labels for better accessibility support.

Overall, this refactored codebase is well-structured and ready for enhancements based on further development needs or feedback.

21 changes: 21 additions & 0 deletions ui/src/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1394,5 +1394,26 @@ export const iconMap: any = {
)
])
}
},
'app-user-input': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 1024 1024',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg'
},
[
h('path', {
d: 'M85.333333 234.666667a149.333333 149.333333 0 0 1 292.48-42.666667H917.333333a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333H377.813333A149.418667 149.418667 0 0 1 85.333333 234.666667z m21.333334 320a21.333333 21.333333 0 0 1-21.333334-21.333334v-42.666666a21.333333 21.333333 0 0 1 21.333334-21.333334h262.186666a149.418667 149.418667 0 0 1 286.293334 0H917.333333a21.333333 21.333333 0 0 1 21.333334 21.333334v42.666666a21.333333 21.333333 0 0 1-21.333334 21.333334h-262.186666a149.418667 149.418667 0 0 1-286.293334 0H106.666667z m405.333333 21.333333a64 64 0 1 0 0-128 64 64 0 0 0 0 128z m-405.333333 256A21.333333 21.333333 0 0 1 85.333333 810.666667v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333h539.52a149.418667 149.418667 0 0 1 292.48 42.666666 149.333333 149.333333 0 0 1-292.48 42.666667H106.666667z m682.666666-106.666667a64 64 0 1 0 0 128 64 64 0 0 0 0-128zM234.666667 298.666667a64 64 0 1 0 0-128 64 64 0 0 0 0 128z',
fill: 'currentColor'
})
]
)
])
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seem to be no errors in this code snippet. The iconMap object is properly structured with an additional entry for 'app-user-input'. The iconReader function returns a JSX component representing an SVG icon that matches the specified key ('app-user-input'). This should work as expected and can be used in components where you need to render icons with different names.

3 changes: 2 additions & 1 deletion ui/src/locales/lang/en-US/ai-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export default {
oppose: 'Dislike',
cancelOppose: 'Undo Dislike',
continue: 'Continue',
stopChat: 'Stop Response'
stopChat: 'Stop Response',
startChat: 'Start Response',
},
tip: {
error500Message: 'Sorry, the service is currently under maintenance. Please try again later!',
Expand Down
3 changes: 2 additions & 1 deletion ui/src/locales/lang/zh-CN/ai-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export default {
oppose: '反对',
cancelOppose: '取消反对',
continue: '继续',
stopChat: '停止回答'
stopChat: '停止回答',
startChat: '开始回答',
},
tip: {
error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!',
Expand Down
3 changes: 2 additions & 1 deletion ui/src/locales/lang/zh-Hant/ai-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export default {
oppose: '反對',
cancelOppose: '取消反對',
continue: '繼續',
stopChat: '停止回答'
stopChat: '停止回答',
startChat: '開始回答',
},
tip: {
error500Message: '抱歉,當前正在維護,無法提供服務,請稍後再試!',
Expand Down
2 changes: 1 addition & 1 deletion ui/src/views/chat/pc/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@
</el-button>
</div>
</div>
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
</div>
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
</template>

<script setup lang="ts">
Expand Down