H-338: close H-335 release blockers (#59)

* H-16: align takeover with channel AI workflow (#2)

* feat(conversations): complete manual AI takeover

* fix(conversations): align AI takeover flow with channel AI

* fix(conversations): close takeover review gaps

---------

Co-authored-by: Rogee <rogee@ipao.vip>

* feat(shangwutong): sync customer names back to channel (#3)

Co-authored-by: Rogee <rogee@ipao.vip>

* fix(shangwutong): close contact sync review gaps (#4)

Co-authored-by: Rogee <rogee@ipao.vip>

* H-28: harden Shangwutong CID sync (#5)

* fix(shangwutong): close contact sync review gaps

* fix(shangwutong): harden CID sync boundaries

---------

Co-authored-by: Rogee <rogee@ipao.vip>

* fix(conversations): sync AI takeover exit in realtime (#6)

Co-authored-by: Rogee <rogee@ipao.vip>

* test(shangwutong): cover CID rename reliability (#7)

Co-authored-by: Rogee <rogee@ipao.vip>

* H-43: fix WEB Captain takeover E2E flow (#8)

* test(shangwutong): cover CID rename reliability

* H-43: fix WEB Captain takeover flow

* H-48: preserve compatible provider model

* H-49: make Captain takeover atomic

* H-50: prevent duplicate widget initialization

---------

Co-authored-by: Rogee <rogee@ipao.vip>

* H-55: make Captain bindings atomic (#9)

Co-authored-by: Rogee <rogee@ipao.vip>

* H-60: harden Captain migration rollback and concurrency

* chore(agent): baseline — uncommitted work from the local directory

* H-335: add safe Captain skills and user deactivation

* H-338: close auth and Captain review blockers

* H-338: close assignment and session races

* H-338: close assignment and websocket invalidation gaps

* H-338: enforce assignment write invariants

---------

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-20 10:21:19 +08:00
committed by GitHub
co-authored by rogee
parent 1d8145f3b5
commit 6c78820a1f
53 changed files with 1534 additions and 216 deletions
@@ -20,6 +20,7 @@
"ACTIONS": "Actions",
"VERIFIED": "Verified",
"VERIFICATION_PENDING": "Verification Pending",
"INACTIVE": "Deactivated",
"AVAILABLE_CUSTOM_ROLE": "Available custom role permissions"
},
"ADD": {
@@ -82,6 +83,10 @@
"PLACEHOLDER": "Please select an availability status",
"ERROR": "Availability is required"
},
"ACTIVE": {
"LABEL": "Sign-in enabled (all accounts)",
"HELP": "Deactivating immediately signs the user out of every account and removes them from assignment lists."
},
"SUBMIT": "Edit Agent"
},
"BUTTON_TEXT": "Edit",
@@ -20,6 +20,7 @@
"ACTIONS": "操作",
"VERIFIED": "已认证",
"VERIFICATION_PENDING": "待验证",
"INACTIVE": "已停用",
"AVAILABLE_CUSTOM_ROLE": "可自定义角色权限"
},
"ADD": {
@@ -82,6 +83,10 @@
"PLACEHOLDER": "请选择一个可用状态",
"ERROR": "需要提供可用性信息"
},
"ACTIVE": {
"LABEL": "启用登录(所有账号)",
"HELP": "停用后将立即退出该用户的所有账号,并从可分配客服列表中移除。"
},
"SUBMIT": "编辑客服"
},
"BUTTON_TEXT": "编辑",
@@ -39,6 +39,10 @@ const props = defineProps({
type: Number,
default: null,
},
active: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['close']);
@@ -50,6 +54,7 @@ const { t } = useI18n();
const agentName = ref(props.name);
const agentAvailability = ref(props.availability);
const agentActive = ref(props.active);
const selectedRoleId = ref(props.customRoleId || props.type);
const temporaryPassword = ref('');
const passwordDialogRef = ref(null);
@@ -128,6 +133,7 @@ const editAgent = async () => {
id: props.id,
name: agentName.value,
availability: agentAvailability.value,
active: agentActive.value,
};
if (selectedRole.value.name.startsWith('custom_')) {
@@ -174,6 +180,16 @@ const resetPassword = async () => {
</label>
</div>
<div class="w-full">
<label class="flex items-center gap-2">
<input v-model="agentActive" type="checkbox" />
<span>{{ $t('AGENT_MGMT.EDIT.FORM.ACTIVE.LABEL') }}</span>
</label>
<p class="text-sm text-n-slate-11">
{{ $t('AGENT_MGMT.EDIT.FORM.ACTIVE.HELP') }}
</p>
</div>
<div class="w-full">
<label :class="{ error: v$.selectedRoleId.$error }">
{{ $t('AGENT_MGMT.EDIT.FORM.AGENT_TYPE.LABEL') }}
@@ -250,6 +250,12 @@ const confirmDeletion = () => {
>
{{ $t('AGENT_MGMT.LIST.VERIFICATION_PENDING') }}
</span>
<span
v-if="!agent.active"
class="text-body-main text-n-ruby-11"
>
{{ $t('AGENT_MGMT.LIST.INACTIVE') }}
</span>
</div>
</div>
</div>
@@ -291,6 +297,7 @@ const confirmDeletion = () => {
:email="currentAgent.email"
:availability="currentAgent.availability_status"
:custom-role-id="currentAgent.custom_role_id"
:active="currentAgent.active"
@close="hideEditPopup"
/>
</woot-modal>