feat: 优化 AI 生成交互体验

- 移除不必要的 loading 状态,简化用户交互
- 在项目和任务生成中添加取消功能,提升用户体验
- 更新相关组件以支持取消操作,确保生成过程的灵活性
This commit is contained in:
kuaifan 2025-09-23 14:41:34 +08:00
parent 7f6abc331b
commit 5fd2505a33
3 changed files with 49 additions and 19 deletions

View File

@ -250,7 +250,6 @@
<div <div
class="project-ai-button" class="project-ai-button"
type="text" type="text"
:loading="projectAiLoading"
@click="onProjectAI"> @click="onProjectAI">
<i class="taskfont">&#xe8a1;</i> <i class="taskfont">&#xe8a1;</i>
</div> </div>
@ -464,7 +463,6 @@ export default {
columns: '', columns: '',
flow: 'open', flow: 'open',
}, },
projectAiLoading: false,
addRule: { addRule: {
name: [ name: [
{ required: true, message: this.$L('请填写项目名称!'), trigger: 'change' }, { required: true, message: this.$L('请填写项目名称!'), trigger: 'change' },
@ -999,7 +997,6 @@ export default {
onAddShow() { onAddShow() {
this.$store.dispatch("getColumnTemplate").catch(() => {}) this.$store.dispatch("getColumnTemplate").catch(() => {})
this.projectAiLoading = false;
this.addShow = true; this.addShow = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.projectName.focus(); this.$refs.projectName.focus();
@ -1007,9 +1004,7 @@ export default {
}, },
onProjectAI() { onProjectAI() {
if (this.projectAiLoading) { let canceled = false;
return;
}
$A.modalInput({ $A.modalInput({
title: 'AI 生成', title: 'AI 生成',
placeholder: '请简要描述项目目标、范围或关键里程碑AI 将生成名称和任务列表', placeholder: '请简要描述项目目标、范围或关键里程碑AI 将生成名称和任务列表',
@ -1019,12 +1014,18 @@ export default {
autosize: {minRows: 2, maxRows: 6}, autosize: {minRows: 2, maxRows: 6},
maxlength: 500, maxlength: 500,
}, },
onCancel: () => {
canceled = true;
},
onOk: (value) => { onOk: (value) => {
if (!value) { if (!value) {
return '请输入项目需求'; return '请输入项目需求';
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.projectAiLoading = true; if (canceled) {
reject();
return;
}
const parseColumns = (cols) => { const parseColumns = (cols) => {
if (Array.isArray(cols)) { if (Array.isArray(cols)) {
return cols; return cols;
@ -1042,10 +1043,6 @@ export default {
columns: parseColumns(item.columns) columns: parseColumns(item.columns)
})); }));
const finish = () => {
this.projectAiLoading = false;
};
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'project/ai/generate', url: 'project/ai/generate',
data: { data: {
@ -1056,6 +1053,10 @@ export default {
}, },
timeout: 45 * 1000, timeout: 45 * 1000,
}).then(({data}) => { }).then(({data}) => {
if (canceled) {
resolve();
return;
}
const columns = Array.isArray(data.columns) ? data.columns : parseColumns(data.columns); const columns = Array.isArray(data.columns) ? data.columns : parseColumns(data.columns);
this.$set(this.addData, 'name', data.name || ''); this.$set(this.addData, 'name', data.name || '');
this.$set(this.addData, 'columns', columns.length > 0 ? columns.join(',') : ''); this.$set(this.addData, 'columns', columns.length > 0 ? columns.join(',') : '');
@ -1064,10 +1065,12 @@ export default {
this.$refs.projectName.focus(); this.$refs.projectName.focus();
} }
}); });
finish();
resolve(); resolve();
}).catch(({msg}) => { }).catch(({msg}) => {
finish(); if (canceled) {
resolve();
return;
}
reject(msg); reject(msg);
}); });
}); });

View File

@ -433,8 +433,6 @@ export default {
showMore: false, showMore: false,
showEmoji: false, showEmoji: false,
chatAiLoading: false,
emojiQuickShow: false, emojiQuickShow: false,
emojiQuickKey: '', emojiQuickKey: '',
emojiQuickItems: [], emojiQuickItems: [],
@ -1823,13 +1821,14 @@ export default {
}, },
onMessageAI() { onMessageAI() {
if (this.disabled || this.chatAiLoading) { if (this.disabled) {
return; return;
} }
if (!this.dialogId) { if (!this.dialogId) {
$A.messageWarning(this.$L('当前未选择会话')); $A.messageWarning(this.$L('当前未选择会话'));
return; return;
} }
let canceled = false;
$A.modalInput({ $A.modalInput({
title: 'AI 生成', title: 'AI 生成',
placeholder: '请简要描述消息的主题、语气或要点AI 将生成完整消息', placeholder: '请简要描述消息的主题、语气或要点AI 将生成完整消息',
@ -1839,12 +1838,18 @@ export default {
autosize: {minRows: 2, maxRows: 6}, autosize: {minRows: 2, maxRows: 6},
maxlength: 500, maxlength: 500,
}, },
onCancel: () => {
canceled = true;
},
onOk: (value) => { onOk: (value) => {
if (!value) { if (!value) {
return '请输入消息需求'; return '请输入消息需求';
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.chatAiLoading = true; if (canceled) {
reject();
return;
}
this.$store.dispatch('call', { this.$store.dispatch('call', {
url: 'dialog/msg/ai_generate', url: 'dialog/msg/ai_generate',
data: { data: {
@ -1856,6 +1861,10 @@ export default {
timeout: 45 * 1000, timeout: 45 * 1000,
}).then(({data}) => { }).then(({data}) => {
const html = data && (data.html || data.text) ? (data.html || data.text) : ''; const html = data && (data.html || data.text) ? (data.html || data.text) : '';
if (canceled) {
resolve();
return;
}
if (!html) { if (!html) {
reject(this.$L('AI 未生成内容')); reject(this.$L('AI 未生成内容'));
return; return;
@ -1864,9 +1873,11 @@ export default {
this.$nextTick(() => this.focus()); this.$nextTick(() => this.focus());
resolve(); resolve();
}).catch(({msg}) => { }).catch(({msg}) => {
if (canceled) {
resolve();
return;
}
reject(msg); reject(msg);
}).finally(() => {
this.chatAiLoading = false;
}); });
}); });
} }

View File

@ -625,6 +625,7 @@ export default {
}, },
onAI() { onAI() {
let canceled = false;
$A.modalInput({ $A.modalInput({
title: 'AI 生成', title: 'AI 生成',
placeholder: '请简要描述任务目标、背景或预期交付AI 将生成标题、详细说明和子任务', placeholder: '请简要描述任务目标、背景或预期交付AI 将生成标题、详细说明和子任务',
@ -634,11 +635,18 @@ export default {
autosize: { minRows: 2, maxRows: 6 }, autosize: { minRows: 2, maxRows: 6 },
maxlength: 500, maxlength: 500,
}, },
onCancel: () => {
canceled = true;
},
onOk: (value) => { onOk: (value) => {
if (!value) { if (!value) {
return `请输入任务描述` return `请输入任务描述`
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (canceled) {
reject();
return;
}
// //
const currentTemplate = this.templateActiveID ? const currentTemplate = this.templateActiveID ?
this.taskTemplateList.find(item => item.id === this.templateActiveID) : null; this.taskTemplateList.find(item => item.id === this.templateActiveID) : null;
@ -660,6 +668,10 @@ export default {
}, },
timeout: 60 * 1000, timeout: 60 * 1000,
}).then(({data}) => { }).then(({data}) => {
if (canceled) {
resolve();
return;
}
this.addData.name = data.title; this.addData.name = data.title;
this.$refs.editorTaskRef.setContent(data.content, {format: 'raw'}); this.$refs.editorTaskRef.setContent(data.content, {format: 'raw'});
if (Array.isArray(data.subtasks) && data.subtasks.length > 0) { if (Array.isArray(data.subtasks) && data.subtasks.length > 0) {
@ -695,6 +707,10 @@ export default {
} }
resolve(); resolve();
}).catch(({msg}) => { }).catch(({msg}) => {
if (canceled) {
resolve();
return;
}
reject(msg); reject(msg);
}); });
}) })