fix(frontend): 修复多处输入框 IME 合成期回车/Backspace 误触发提交

- file.vue 块模式文件重命名输入框 @on-keyup → @on-keydown,
  避免拼音选词回车的 keyup 阶段误触发提交
- TagInput 回车添加 tag、Backspace 删除 tag 增加 IME 守卫
  (isComposing / key=Process / keyCode=229),避免拼音选词回车
  误加 tag、合成期 Backspace 误删上一个 tag
- login / ProjectPanel / UserTagsModal / TaskAdd 的 @on-enter
  改用 @on-keydown 包装 (keyCode===13),绕开 iview Input
  handleEnter 走 keyup.enter 在 IME 选词回车会误触发提交的问题

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kuaifan 2026-06-14 23:03:01 +00:00
parent cf6f6041b6
commit 3f5078ec9b
6 changed files with 56 additions and 20 deletions

View File

@ -18,7 +18,7 @@
:placeholder="tis || placeholderText" :placeholder="tis || placeholderText"
:enterkeyhint="enterkeyhint" :enterkeyhint="enterkeyhint"
@keydown.enter="downEnter($event)" @keydown.enter="downEnter($event)"
@keydown.delete="delTag(false)" @keydown.delete="onBackspace($event)"
@keyup="onKeyup" @keyup="onKeyup"
@focus="onFocus" @focus="onFocus"
@blur="onBlur" @blur="onBlur"
@ -195,7 +195,20 @@
this.addTag(false, content) this.addTag(false, content)
}, },
downEnter(e) { downEnter(e) {
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) {
return;
}
e.preventDefault(); e.preventDefault();
this.addTag(e, this.content);
this.$nextTick(() => {
this.$emit("on-enter", e)
})
},
onBackspace(e) {
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) {
return;
}
this.delTag(false);
}, },
onFocus(e) { onFocus(e) {
this.isFocus = true; this.isFocus = true;
@ -207,14 +220,7 @@
this.$emit("on-blur", e) this.$emit("on-blur", e)
}, },
onKeyup(e) { onKeyup(e) {
this.addTag(e, this.content);
//
this.$emit("on-keyup", e) this.$emit("on-keyup", e)
if (e.keyCode === 13) {
this.$nextTick(() => {
this.$emit("on-enter", e)
})
}
}, },
addTag(e, content) { addTag(e, content) {
if (e === false || e.keyCode === 13) { if (e === false || e.keyCode === 13) {

View File

@ -25,7 +25,9 @@
</div> </div>
</transition> </transition>
<transition name="login-mode"> <transition name="login-mode">
<div v-if="loginMode=='access'" class="login-access"> <div
v-if="loginMode=='access'"
class="login-access">
<Input <Input
v-if="$isSoftware && cacheServerUrl" v-if="$isSoftware && cacheServerUrl"
:value="$A.getDomain(cacheServerUrl)" :value="$A.getDomain(cacheServerUrl)"
@ -42,7 +44,7 @@
:placeholder="$L('输入您的电子邮件')" :placeholder="$L('输入您的电子邮件')"
type="email" type="email"
size="large" size="large"
@on-enter="onLogin" @on-keydown="onLoginKeydown"
@on-blur="onBlur" @on-blur="onBlur"
clearable/> clearable/>
@ -53,7 +55,7 @@
:placeholder="$L('输入您的密码')" :placeholder="$L('输入您的密码')"
type="password" type="password"
size="large" size="large"
@on-enter="onLogin" @on-keydown="onLoginKeydown"
clearable/> clearable/>
<Input <Input
@ -64,7 +66,7 @@
:placeholder="$L('输入确认密码')" :placeholder="$L('输入确认密码')"
type="password" type="password"
size="large" size="large"
@on-enter="onLogin" @on-keydown="onLoginKeydown"
clearable/> clearable/>
<Input <Input
v-if="loginType=='reg' && needInvite" v-if="loginType=='reg' && needInvite"
@ -74,7 +76,7 @@
:placeholder="$L('请输入注册邀请码')" :placeholder="$L('请输入注册邀请码')"
type="text" type="text"
size="large" size="large"
@on-enter="onLogin" @on-keydown="onLoginKeydown"
clearable><span slot="prepend">&nbsp;{{$L('邀请码')}}&nbsp;</span></Input> clearable><span slot="prepend">&nbsp;{{$L('邀请码')}}&nbsp;</span></Input>
<Input <Input
@ -85,7 +87,7 @@
:placeholder="$L('输入图形验证码')" :placeholder="$L('输入图形验证码')"
type="text" type="text"
size="large" size="large"
@on-enter="onLogin" @on-keydown="onLoginKeydown"
clearable> clearable>
<Icon type="ios-checkmark-circle-outline" class="login-icon" slot="prepend"></Icon> <Icon type="ios-checkmark-circle-outline" class="login-icon" slot="prepend"></Icon>
<div slot="append" class="login-code-end" @click="refreshCode"> <div slot="append" class="login-code-end" @click="refreshCode">
@ -499,6 +501,12 @@ export default {
} }
}, },
onLoginKeydown(e) {
if (e.keyCode === 13) {
this.onLogin();
}
},
onLogin() { onLogin() {
this.chackServerUrl(true).then(() => { this.chackServerUrl(true).then(() => {
this.email = $A.trim(this.email) this.email = $A.trim(this.email)

View File

@ -268,7 +268,7 @@
ref="addColumnName" ref="addColumnName"
v-model="addColumnName" v-model="addColumnName"
@on-blur="addColumnBlur" @on-blur="addColumnBlur"
@on-enter="addColumnSubmit" @on-keydown="onAddColumnKeydown"
@on-clear="addColumnShow=false" @on-clear="addColumnShow=false"
:placeholder="$L('列表名称,回车创建')" :placeholder="$L('列表名称,回车创建')"
clearable/> clearable/>
@ -1373,6 +1373,12 @@ export default {
} }
}, },
onAddColumnKeydown(e) {
if (e.keyCode === 13) {
this.addColumnSubmit();
}
},
addColumnSubmit() { addColumnSubmit() {
let name = this.addColumnName.trim(); let name = this.addColumnName.trim();
if (name === '' || this.addColumnLoad) { if (name === '' || this.addColumnLoad) {

View File

@ -173,7 +173,7 @@
type="text" type="text"
v-model="subName" v-model="subName"
:class="['enter-input', subName == '' ? 'empty' : '']" :class="['enter-input', subName == '' ? 'empty' : '']"
@on-enter="addSubTask" @on-keydown="onSubNameKeydown"
:placeholder="$L('+ 输入子任务,回车添加子任务')"/> :placeholder="$L('+ 输入子任务,回车添加子任务')"/>
</div> </div>
</Form> </Form>
@ -469,6 +469,12 @@ export default {
} }
}, },
onSubNameKeydown(e) {
if (e.keyCode === 13) {
this.addSubTask();
}
},
addSubTask() { addSubTask() {
if (this.subName.trim() !== '') { if (this.subName.trim() !== '') {
this.addData.subtasks.push({ this.addData.subtasks.push({

View File

@ -14,7 +14,7 @@
:maxlength="20" :maxlength="20"
:disabled="pending.add" :disabled="pending.add"
:placeholder="$L('请输入个性标签')" :placeholder="$L('请输入个性标签')"
@on-enter="handleAdd"> @on-keydown="onAddKeydown">
<Button <Button
slot="append" slot="append"
type="primary" type="primary"
@ -47,7 +47,7 @@
v-model="editName" v-model="editName"
:maxlength="20" :maxlength="20"
:disabled="isPending(tag.id, 'edit')" :disabled="isPending(tag.id, 'edit')"
@on-enter="confirmEdit(tag)"/> @on-keydown="onEditKeydown($event, tag)"/>
</div> </div>
<div class="tag-actions"> <div class="tag-actions">
<Button <Button
@ -223,6 +223,16 @@ export default {
} }
}); });
}, },
onAddKeydown(e) {
if (e.keyCode === 13) {
this.handleAdd();
}
},
onEditKeydown(e, tag) {
if (e.keyCode === 13) {
this.confirmEdit(tag);
}
},
handleAdd() { handleAdd() {
const name = this.newTagName.trim(); const name = this.newTagName.trim();
if (!name) { if (!name) {

View File

@ -185,7 +185,7 @@
:disabled="!!item._load" :disabled="!!item._load"
:parser="onParser" :parser="onParser"
@on-blur="onBlur(item)" @on-blur="onBlur(item)"
@on-keyup="onKeyup($event, item)"/> @on-keydown="onKeydown($event, item)"/>
<div v-if="item._load" class="file-load"><Loading/></div> <div v-if="item._load" class="file-load"><Loading/></div>
</div> </div>
<div v-else class="file-name" :title="item.name">{{$A.getFileName(item)}}</div> <div v-else class="file-name" :title="item.name">{{$A.getFileName(item)}}</div>
@ -1989,7 +1989,7 @@ export default {
this.onEnter(item); this.onEnter(item);
}, },
onKeyup(e, item) { onKeydown(e, item) {
if (e.keyCode === 13) { if (e.keyCode === 13) {
this.onEnter(item); this.onEnter(item);
} else if (e.keyCode === 27) { } else if (e.keyCode === 27) {